diff --git a/.eslintignore b/.eslintignore index 08e37e82948a34..2577b07cec12e8 100644 --- a/.eslintignore +++ b/.eslintignore @@ -4,6 +4,7 @@ build-module node_modules packages/block-serialization-spec-parser/parser.js packages/e2e-tests/plugins +packages/react-native-editor/bundle playground/dist vendor wordpress diff --git a/.eslintrc.js b/.eslintrc.js index 9f7da03674a7df..a4a1ec153e3b2d 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -38,10 +38,22 @@ module.exports = { globals: { wp: 'off', }, + settings: { + jsdoc: { + mode: 'typescript', + }, + }, rules: { + 'jest/expect-expect': 'off', '@wordpress/dependency-group': 'error', '@wordpress/gutenberg-phase': 'error', '@wordpress/react-no-unsafe-timeout': 'error', + '@wordpress/i18n-text-domain': [ + 'error', + { + allowedTextDomain: 'default', + }, + ], 'no-restricted-syntax': [ 'error', // NOTE: We can't include the forward slash in our regex or @@ -67,29 +79,6 @@ module.exports = { message: 'Deprecated functions must be removed before releasing this version.', }, - { - selector: - 'CallExpression[callee.name=/^(__|_n|_nx|_x)$/]:not([arguments.0.type=/^Literal|BinaryExpression$/])', - message: - 'Translate function arguments must be string literals.', - }, - { - selector: - 'CallExpression[callee.name=/^(_n|_nx|_x)$/]:not([arguments.1.type=/^Literal|BinaryExpression$/])', - message: - 'Translate function arguments must be string literals.', - }, - { - selector: - 'CallExpression[callee.name=_nx]:not([arguments.3.type=/^Literal|BinaryExpression$/])', - message: - 'Translate function arguments must be string literals.', - }, - { - selector: - 'CallExpression[callee.name=/^(__|_x|_n|_nx)$/] Literal[value=/\\.{3}/]', - message: 'Use ellipsis character (…) in place of three dots', - }, { selector: 'ImportDeclaration[source.value="redux"] Identifier.imported[name="combineReducers"]', @@ -179,6 +168,9 @@ module.exports = { { files: [ 'packages/e2e-test*/**/*.js' ], extends: [ 'plugin:@wordpress/eslint-plugin/test-e2e' ], + rules: { + 'jest/expect-expect': 'off', + }, }, ], }; diff --git a/.github/ISSUE_TEMPLATE/Bug_report.md b/.github/ISSUE_TEMPLATE/Bug_report.md index 20aa7016d17e90..0c5bcb7b300122 100644 --- a/.github/ISSUE_TEMPLATE/Bug_report.md +++ b/.github/ISSUE_TEMPLATE/Bug_report.md @@ -20,6 +20,11 @@ A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem. +**Editor version (please complete the following information):** +- WordPress version: [e.g: 5.3.2] +- Does the website has Gutenberg plugin installed, or is it using the block editor that comes by default? [e.g: "gutenberg plugin", "default"] +- If the Gutenberg plugin is installed, which version is it? [e.g., 7.6] + **Desktop (please complete the following information):** - OS: [e.g. iOS] - Browser [e.g. chrome, safari] @@ -32,5 +37,4 @@ If applicable, add screenshots to help explain your problem. - Version [e.g. 22] **Additional context** -- Please add the version of Gutenberg you are using in the description. - To report a security issue, please visit the WordPress HackerOne program: https://hackerone.com/wordpress. diff --git a/.gitignore b/.gitignore index fc31278c325ded..a3ebac937fc66c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ build build-module build-style +build-types node_modules gutenberg.zip @@ -14,6 +15,7 @@ yarn.lock playground/dist .cache +*.tsbuildinfo # Report generated from jest-junit test/native/junit.xml diff --git a/.prettierrc.js b/.prettierrc.js index 0605f83bf90782..51b8aeb41505a6 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -1,3 +1,3 @@ // Import the default config file and expose it in the project root. // Useful for editor integrations. -module.exports = require( '@wordpress/scripts/config/.prettierrc.js' ); +module.exports = require( '@wordpress/prettier-config' ); diff --git a/.travis.yml b/.travis.yml index 8798f87bb55da5..b39f8565c5683a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,10 +24,8 @@ branches: env: global: - - PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true - WP_DEVELOP_DIR: ./wordpress - LOCAL_SCRIPT_DEBUG: false - - INSTALL_COMPOSER: false - INSTALL_WORDPRESS: true # Make sure NodeGit gets the correct C libs. @@ -89,10 +87,6 @@ install: npm run env connect npm run env cli plugin activate gutenberg fi - - | - if [[ "$INSTALL_COMPOSER" = "true" ]]; then - npm run env docker-run -- php composer install - fi - | if [[ "$E2E_ROLE" = "author" ]]; then npm run env cli -- user create author author@example.com --role=author --user_pass=authpass @@ -114,6 +108,13 @@ jobs: script: - npx eslint --parser-options=ecmaVersion:5 --no-eslintrc --no-ignore ./build/**/*.js + - name: Typecheck + install: + - npm ci + script: + - npm run build:package-types + + - name: Build artifacts install: # A "full" install is executed, since `npm ci` does not always exit @@ -152,79 +153,61 @@ jobs: - npm run test-unit:native -- --ci --maxWorkers=2 --cacheDirectory="$HOME/.jest-cache" - name: PHP unit tests - env: INSTALL_COMPOSER=true script: - npm run test-php && npm run test-unit-php-multisite - name: PHP unit tests (PHP 5.6) - env: INSTALL_COMPOSER=true LOCAL_PHP=5.6-fpm + env: LOCAL_PHP=5.6-fpm script: - npm run test-php && npm run test-unit-php-multisite - name: E2E tests (Admin) (1/4) - env: FORCE_REDUCED_MOTION=true PUPPETEER_SKIP_CHROMIUM_DOWNLOAD= + env: FORCE_REDUCED_MOTION=true script: - $( npm bin )/wp-scripts test-e2e --config=./packages/e2e-tests/jest.config.js --listTests > ~/.jest-e2e-tests - $( npm bin )/wp-scripts test-e2e --config=./packages/e2e-tests/jest.config.js --cacheDirectory="$HOME/.jest-cache" --runTestsByPath $( awk 'NR % 4 == 0' < ~/.jest-e2e-tests ) - name: E2E tests (Admin) (2/4) - env: FORCE_REDUCED_MOTION=true PUPPETEER_SKIP_CHROMIUM_DOWNLOAD= + env: FORCE_REDUCED_MOTION=true script: - $( npm bin )/wp-scripts test-e2e --config=./packages/e2e-tests/jest.config.js --listTests > ~/.jest-e2e-tests - $( npm bin )/wp-scripts test-e2e --config=./packages/e2e-tests/jest.config.js --cacheDirectory="$HOME/.jest-cache" --runTestsByPath $( awk 'NR % 4 == 1' < ~/.jest-e2e-tests ) - name: E2E tests (Admin) (3/4) - env: FORCE_REDUCED_MOTION=true PUPPETEER_SKIP_CHROMIUM_DOWNLOAD= + env: FORCE_REDUCED_MOTION=true script: - $( npm bin )/wp-scripts test-e2e --config=./packages/e2e-tests/jest.config.js --listTests > ~/.jest-e2e-tests - $( npm bin )/wp-scripts test-e2e --config=./packages/e2e-tests/jest.config.js --cacheDirectory="$HOME/.jest-cache" --runTestsByPath $( awk 'NR % 4 == 2' < ~/.jest-e2e-tests ) - name: E2E tests (Admin) (4/4) - env: FORCE_REDUCED_MOTION=true PUPPETEER_SKIP_CHROMIUM_DOWNLOAD= + env: FORCE_REDUCED_MOTION=true script: - $( npm bin )/wp-scripts test-e2e --config=./packages/e2e-tests/jest.config.js --listTests > ~/.jest-e2e-tests - $( npm bin )/wp-scripts test-e2e --config=./packages/e2e-tests/jest.config.js --cacheDirectory="$HOME/.jest-cache" --runTestsByPath $( awk 'NR % 4 == 3' < ~/.jest-e2e-tests ) - name: E2E tests (Author) (1/4) - env: E2E_ROLE=author FORCE_REDUCED_MOTION=true PUPPETEER_SKIP_CHROMIUM_DOWNLOAD= + env: E2E_ROLE=author FORCE_REDUCED_MOTION=true script: - $( npm bin )/wp-scripts test-e2e --config=./packages/e2e-tests/jest.config.js --listTests > ~/.jest-e2e-tests - $( npm bin )/wp-scripts test-e2e --config=./packages/e2e-tests/jest.config.js --cacheDirectory="$HOME/.jest-cache" --runTestsByPath $( awk 'NR % 4 == 0' < ~/.jest-e2e-tests ) - name: E2E tests (Author) (2/4) - env: E2E_ROLE=author FORCE_REDUCED_MOTION=true PUPPETEER_SKIP_CHROMIUM_DOWNLOAD= + env: E2E_ROLE=author FORCE_REDUCED_MOTION=true script: - $( npm bin )/wp-scripts test-e2e --config=./packages/e2e-tests/jest.config.js --listTests > ~/.jest-e2e-tests - $( npm bin )/wp-scripts test-e2e --config=./packages/e2e-tests/jest.config.js --cacheDirectory="$HOME/.jest-cache" --runTestsByPath $( awk 'NR % 4 == 1' < ~/.jest-e2e-tests ) - name: E2E tests (Author) (3/4) - env: E2E_ROLE=author FORCE_REDUCED_MOTION=true PUPPETEER_SKIP_CHROMIUM_DOWNLOAD= + env: E2E_ROLE=author FORCE_REDUCED_MOTION=true script: - $( npm bin )/wp-scripts test-e2e --config=./packages/e2e-tests/jest.config.js --listTests > ~/.jest-e2e-tests - $( npm bin )/wp-scripts test-e2e --config=./packages/e2e-tests/jest.config.js --cacheDirectory="$HOME/.jest-cache" --runTestsByPath $( awk 'NR % 4 == 2' < ~/.jest-e2e-tests ) - name: E2E tests (Author) (4/4) - env: E2E_ROLE=author FORCE_REDUCED_MOTION=true PUPPETEER_SKIP_CHROMIUM_DOWNLOAD= + env: E2E_ROLE=author FORCE_REDUCED_MOTION=true script: - $( npm bin )/wp-scripts test-e2e --config=./packages/e2e-tests/jest.config.js --listTests > ~/.jest-e2e-tests - $( npm bin )/wp-scripts test-e2e --config=./packages/e2e-tests/jest.config.js --cacheDirectory="$HOME/.jest-cache" --runTestsByPath $( awk 'NR % 4 == 3' < ~/.jest-e2e-tests ) - - stage: deploy - if: (NOT type IN (pull_request)) AND (branch = master) - name: Deploy Playground - env: INSTALL_WORDPRESS=false - install: - - npm ci - before_deploy: - - npm run storybook:build - deploy: - provider: pages - skip_cleanup: true - github_token: $GITHUB_TOKEN - keep_history: true - local_dir: playground/dist - on: - branch: master - allow_failures: # nothing is allowed to fail at the moment diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bb46ac5f3a2385..9381a3cd9f2af5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,7 +12,7 @@ To learn all about contributing to the Gutenberg project, see the [Contributor G - Documentation? See the [documentation section](/docs/contributors/document.md). -- Triage? We need help reviewing existing issues to make sure they’re relevant and actionable. Triage is an important contribution because it allows us to work on the highest priority issues. To learn more, please see the [triaging issues section](docs/contributors/repository-management.md#triaging-issues). +- Triage? We need help reviewing existing issues to make sure they’re relevant and actionable. Triage is an important contribution because it allows us to work on the highest priority issues. To learn more, please see the [triaging issues section](docs/contributors/triage.md). ## Guidelines diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index e1ed7443bbf027..9a845864a4a459 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -145,3 +145,4 @@ This list is manually curated to include valuable contributions by volunteers th | @akkspros | @passoniate | | @anthonyledesma | @paranoia1906 | | @richtabor | @richtabor | +| @mikehaydon | @intelliwolf | diff --git a/bin/api-docs/are-api-docs-unstaged.js b/bin/api-docs/are-api-docs-unstaged.js new file mode 100644 index 00000000000000..b7d956b9e145c3 --- /dev/null +++ b/bin/api-docs/are-api-docs-unstaged.js @@ -0,0 +1,43 @@ +#!/usr/bin/env node + +/** + * Node dependencies. + */ +const { extname } = require( 'path' ); +const chalk = require( 'chalk' ); +const execSync = require( 'child_process' ).execSync; +const { readFile } = require( 'fs' ).promises; + +const getUnstagedFiles = () => + execSync( 'git diff --name-only', { encoding: 'utf8' } ) + .split( '\n' ) + .filter( Boolean ); + +const fileHasToken = async ( file ) => + ( await readFile( file, 'utf8' ) ).includes( ' + * // content within will be filled by docgen + * + * + * @example Delimiter tokens that use a specific source file: + * + * // content within will be filled by docgen + * + * + * @type {RegExp} + * @see DEFAULT_PATH + */ +const TOKEN_PATTERN = //g; + +/** + * Given an absolute file path, returns the package name. + * + * @param {string} file Absolute path. + * + * @return {string} Package name. + */ +function getFilePackage( file ) { + return relative( PACKAGES_DIR, file ).split( sep )[ 0 ]; +} + +/** + * Returns an appropriate glob pattern for the packages directory to match + * relevant documentation files for a given set of files. + * + * @param {string[]} files Set of files to match. Pass an empty set to match + * all packages. + * + * @return {string} Packages glob pattern. + */ +function getPackagePattern( files ) { + if ( ! files.length ) { + return '*'; + } + + // Since brace expansion doesn't work with a single package, special-case + // the pattern for the singular match. + const packages = Array.from( new Set( files.map( getFilePackage ) ) ); + return packages.length === 1 ? packages[ 0 ] : '{' + packages.join() + '}'; +} + +/** + * Returns the conventional store name of a given package. + * + * @param {string} packageName Package name. + * + * @return {string} Store name. + */ +function getPackageStoreName( packageName ) { + let storeName = 'core'; + if ( packageName !== 'core-data' ) { + storeName += '/' + packageName; + } + + return storeName; +} + +/** + * Returns the conventional documentation file name of a given package. + * + * @param {string} packageName Package name. + * + * @return {string} Documentation file name. + */ +function getDataDocumentationFile( packageName ) { + const storeName = getPackageStoreName( packageName ); + return `data-${ storeName.replace( '/', '-' ) }.md`; +} + +/** + * Returns an appropriate glob pattern for the data documentation directory to + * match relevant documentation files for a given set of files. + * + * @param {string[]} files Set of files to match. Pass an empty set to match + * all packages. + * + * @return {string} Packages glob pattern. + */ +function getDataDocumentationPattern( files ) { + if ( ! files.length ) { + return '*'; + } + + // Since brace expansion doesn't work with a single package, special-case + // the pattern for the singular match. + const filePackages = Array.from( new Set( files.map( getFilePackage ) ) ); + const docFiles = filePackages.map( getDataDocumentationFile ); + + return docFiles.length === 1 ? docFiles[ 0 ] : '{' + docFiles.join() + '}'; +} + +/** + * Stream transform which filters out README files to include only those + * containing matched token pattern, yielding a tuple of the file and its + * matched tokens. + * + * @type {Transform} + */ +const filterTokenTransform = new Transform( { + objectMode: true, + + async transform( file, _encoding, callback ) { + let content; + try { + content = await readFile( file, 'utf8' ); + } catch {} + + if ( content ) { + const tokens = []; + + for ( const match of content.matchAll( TOKEN_PATTERN ) ) { + const [ , token, path = DEFAULT_PATH ] = match; + tokens.push( [ token, path ] ); + } + + if ( tokens.length ) { + this.push( [ file, tokens ] ); + } + } + + callback(); + }, +} ); + +/** + * Optional process arguments for which to generate documentation. + * + * @type {string[]} + */ +const files = process.argv.slice( 2 ); + +glob.stream( [ + `${ PACKAGES_DIR }/${ getPackagePattern( files ) }/README.md`, + `${ DATA_DOCS_DIR }/${ getDataDocumentationPattern( files ) }`, +] ) + .pipe( filterTokenTransform ) + .on( 'data', async ( /** @type {WPReadmeFileData} */ data ) => { + const [ file, tokens ] = data; + const output = relative( ROOT_DIR, file ); + + // Each file can have more than one placeholder content to update, each + // represented by tokens. The docgen script updates one token at a time, + // so the tokens must be replaced in sequence to prevent the processes + // from overriding each other. + for ( const [ token, path ] of tokens ) { + try { + await execa( + join( + __dirname, + '..', + '..', + 'node_modules', + '.bin', + 'docgen' + ), + [ + relative( ROOT_DIR, resolve( dirname( file ), path ) ), + `--output ${ output }`, + '--to-token', + `--use-token "${ token }"`, + '--ignore "/unstable|experimental/i"', + ], + { shell: true } + ); + } catch ( error ) { + // Disable reason: Errors should log to console. + + // eslint-disable-next-line no-console + console.error( error ); + process.exit( 1 ); + } + } + } ); diff --git a/bin/api-docs/update-readmes.js b/bin/api-docs/update-readmes.js deleted file mode 100755 index ab1805c3fdeccd..00000000000000 --- a/bin/api-docs/update-readmes.js +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Node dependencies. - */ -const { join } = require( 'path' ); -const spawnSync = require( 'child_process' ).spawnSync; - -/** - * Local dependencies. - */ -const getPackages = require( './packages' ); - -getPackages().forEach( ( entry ) => { - const [ packageName, targetFiles ] = entry; - - Object.entries( targetFiles ).forEach( ( [ token, path ] ) => { - // Each target operates over the same file, so it needs to be processed synchronously, - // as to make sure the processes don't overwrite each other. - const { status, stderr } = spawnSync( - join( - __dirname, - '..', - '..', - 'node_modules', - '.bin', - 'docgen' - ).replace( / /g, '\\ ' ), - [ - join( 'packages', packageName, path ), - `--output packages/${ packageName }/README.md`, - '--to-token', - `--use-token "${ token }"`, - '--ignore "/unstable|experimental/i"', - ], - { shell: true } - ); - - if ( status !== 0 ) { - process.stderr.write( `${ packageName } ${ stderr.toString() }\n` ); - process.exit( 1 ); - } - } ); -} ); diff --git a/bin/build-plugin-zip.sh b/bin/build-plugin-zip.sh index 4aea6ac016c1e8..26ef45f7b337f4 100755 --- a/bin/build-plugin-zip.sh +++ b/bin/build-plugin-zip.sh @@ -99,7 +99,7 @@ done # Run the build. status "Installing dependencies... πŸ“¦" -PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true npm install +npm install status "Generating build... πŸ‘·β€β™€οΈ" npm run build diff --git a/bin/check-latest-npm.js b/bin/check-latest-npm.js new file mode 100644 index 00000000000000..030cff774f0fd7 --- /dev/null +++ b/bin/check-latest-npm.js @@ -0,0 +1,121 @@ +#!/usr/bin/env node + +/** + * External dependencies + */ +const { green, red, yellow } = require( 'chalk' ); +const { get } = require( 'https' ); +const { spawn } = require( 'child_process' ); + +/** + * Returns a promise resolving with the version number of the latest available + * version of NPM. + * + * @return {Promise} Promise resolving with latest NPM version. + */ +async function getLatestNPMVersion() { + return new Promise( ( resolve, reject ) => { + get( + 'https://registry.npmjs.org/npm', + { + headers: { + // By passing a specialized `Accept` header, the registry + // will return an abbreviated form of the package data which + // includes enough detail to determine the latest version. + // + // See: https://github.com/npm/registry/blob/master/docs/responses/package-metadata.md + Accept: 'application/vnd.npm.install-v1+json', + }, + }, + async ( response ) => { + if ( response.statusCode !== 200 ) { + return reject( + new Error( 'Package data for NPM not found' ) + ); + } + + let body = ''; + for await ( const chunk of response ) { + body += chunk.toString(); + } + + let data; + try { + data = JSON.parse( body ); + } catch { + return reject( + new Error( + 'Package data for NPM returned invalid response body' + ) + ); + } + + resolve( data[ 'dist-tags' ].latest ); + } + ).on( 'error', ( error ) => { + if ( + /** @type {NodeJS.ErrnoException} */ ( error ).code === + 'ENOTFOUND' + ) { + error = new Error( `Could not contact the NPM registry to determine latest version. + +This could be due to an intermittent outage of the service, or because you are not connected to the internet. + +Because it is important that \`package-lock.json\` files only be committed while running the latest version of NPM, this commit has been blocked. + +If you are certain of your changes and desire to commit anyways, you should either connect to the internet or bypass commit verification using ${ yellow( + 'git commit --no-verify' + ) } .` ); + } + + reject( error ); + } ); + } ); +} + +/** + * Returns a promise resolving with the version number of the local installed + * version of NPM. + * + * @return {Promise} Promise resolving with local installed NPM version. + */ +async function getLocalNPMVersion() { + return new Promise( async ( resolve ) => { + const childProcess = spawn( 'npm', [ '-v' ] ); + + let output = ''; + for await ( const chunk of childProcess.stdout ) { + output += chunk.toString(); + } + + resolve( output.trim() ); + } ); +} + +Promise.all( [ getLatestNPMVersion(), getLocalNPMVersion() ] ) + .then( ( [ latest, local ] ) => { + if ( latest !== local ) { + throw new Error( + `The local NPM version does not match the expected latest version. Expected ${ green( + latest + ) }, found ${ red( local ) }. + +It is required that you have the latest version of NPM installed in order to commit a change to the package-lock.json file. + +Run ${ yellow( + 'npm install --global npm@latest' + ) } to install the latest version of NPM. Before retrying your commit, run ${ yellow( + 'npm install' + ) } once more to ensure the package-lock.json contents are correct. If there are any changes to the file, they should be included in your commit.` + ); + } + } ) + .catch( ( error ) => { + // Disable reason: A failure should log to the terminal. + + // eslint-disable-next-line no-console + console.error( + 'Latest NPM check failed!\n\n' + error.toString() + '\n' + ); + process.exitCode = 1; + } ); diff --git a/bin/commander.js b/bin/commander.js index 788019da2148b8..54b31c7c360f80 100755 --- a/bin/commander.js +++ b/bin/commander.js @@ -16,7 +16,7 @@ const SimpleGit = require( 'simple-git/promise' ); const childProcess = require( 'child_process' ); const Octokit = require( '@octokit/rest' ); const os = require( 'os' ); -const uuid = require( 'uuid/v4' ); +const { v4: uuid } = require( 'uuid' ); // Config const gitRepoOwner = 'WordPress'; diff --git a/bin/packages/lint-staged-typecheck.js b/bin/packages/lint-staged-typecheck.js new file mode 100644 index 00000000000000..47116c6e99f920 --- /dev/null +++ b/bin/packages/lint-staged-typecheck.js @@ -0,0 +1,39 @@ +/** + * External dependencies + */ +const _ = require( 'lodash' ); +const path = require( 'path' ); +const fs = require( 'fs' ); +const execa = require( 'execa' ); + +/** + * Internal dependencies + */ +require( './validate-typescript-version' ); + +/* eslint-disable no-console */ + +const repoRoot = path.join( __dirname, '..', '..' ); +const tscPath = path.join( repoRoot, 'node_modules', '.bin', 'tsc' ); + +// lint-staged passes full paths to staged changes +const changedFiles = process.argv.slice( 2 ); + +// Transform changed files to package directories containing tsconfig.json +const changedPackages = _.uniq( + changedFiles.map( ( fullPath ) => { + const relativePath = path.relative( repoRoot, fullPath ); + return path.join( ...relativePath.split( path.sep ).slice( 0, 2 ) ); + } ) +).filter( ( packageRoot ) => + fs.existsSync( path.join( packageRoot, 'tsconfig.json' ) ) +); + +try { + execa.sync( tscPath, [ '--build', ...changedPackages ] ); +} catch ( err ) { + console.error( err.stdout ); + process.exitCode = 1; +} + +/* eslint-enable no-console */ diff --git a/bin/packages/validate-typescript-version.js b/bin/packages/validate-typescript-version.js new file mode 100644 index 00000000000000..1c8af56b14bca7 --- /dev/null +++ b/bin/packages/validate-typescript-version.js @@ -0,0 +1,28 @@ +/** + * External dependencies + */ +const tscDetectedVersion = require( 'typescript' ).version; + +/** + * Internal dependencies + */ +const tscDependencyVersion = require( '../../package.json' ).devDependencies + .typescript; + +/* eslint-disable no-console */ + +if ( tscDependencyVersion !== tscDetectedVersion ) { + console.error( + [ + 'TypeScript dependency out of date.', + '\tDetected: %o', + '\tRequired: %o', + 'Please ensure dependencies are up to date.', + ].join( require( 'os' ).EOL ), + tscDetectedVersion, + tscDependencyVersion + ); + process.exit( 1 ); +} + +/* eslint-enable no-console */ diff --git a/bin/tsconfig.json b/bin/tsconfig.json new file mode 100644 index 00000000000000..b65a74eeb1bfc1 --- /dev/null +++ b/bin/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "../tsconfig.base.json", + "compilerOptions": { + "module": "commonjs", + "esModuleInterop": true, + "target": "ES6", + "lib": [ "ES6", "ES2020.string" ], + "rootDir": ".", + "declarationMap": false, + + // We're not interested in the output, but we must generate + // something as part of a composite project. Use the + // ignored `.cache` file to hide tsbuildinfo and d.ts files. + "outDir": ".cache" + }, + "files": [ + "./api-docs/update-api-docs.js", + "./check-latest-npm.js" + ] +} diff --git a/changelog.txt b/changelog.txt index 55a5d52c3441fa..dcc7411387f7d0 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,352 @@ == Changelog == += 7.9.1 = + +### Bug Fixes + + - Make sidebar plugins pinned by default. + - Fix the button styles for old content. + + += 7.9.0 = + +### Features + +- Add gradients support to Group, Columns and Media & Text blocks. [21375](https://github.com/WordPress/gutenberg/pull/21375) +- Add line height support to the Paragraph block. [20775](https://github.com/WordPress/gutenberg/pull/20775) +- Add font size support to the Heading block. [21431](https://github.com/WordPress/gutenberg/pull/21431) +- Add line height support to the Heading block. [21215](https://github.com/WordPress/gutenberg/pull/21215) +- Add custom height unit support to the Cover block. [20888](https://github.com/WordPress/gutenberg/pull/20888) + +### Enhancements + +- New Patterns: + - Hero Two Columns [21128](https://github.com/WordPress/gutenberg/pull/21128) + - Numbered Features [21131](https://github.com/WordPress/gutenberg/pull/21131) + - It's Time [21132](https://github.com/WordPress/gutenberg/pull/21132) +- Add a new keyboard shortcut to toggle Fullscreen Mode. [21436](https://github.com/WordPress/gutenberg/pull/21436) +- Insert post title instead of URL, when adding a link to an existing post [21240](https://github.com/WordPress/gutenberg/pull/21240) +- Social links block: + - Update tumblr icon [21329](https://github.com/WordPress/gutenberg/pull/21329) + - Update and massage social links colors. [21474](https://github.com/WordPress/gutenberg/pull/21474) +- Allow reusable block top and bottom paddings to collapse. [21472](https://github.com/WordPress/gutenberg/pull/21472) +- Update all block previews to use the auto-height behavior. [21014](https://github.com/WordPress/gutenberg/pull/21014) +- Disable autocomplete for custom class name inputs. [21110](https://github.com/WordPress/gutenberg/pull/21110) +- Several small tweaks to the new Block UI. [21476](https://github.com/WordPress/gutenberg/pull/21476) +- Unify the focus styles across the UI. [21141](https://github.com/WordPress/gutenberg/pull/21141) +- Improve block focus style. [21498](https://github.com/WordPress/gutenberg/pull/21498) +- Remove the post permalink UI from the post title. [21099](https://github.com/WordPress/gutenberg/pull/21099) +- Style the default toolbar buttons. [21252](https://github.com/WordPress/gutenberg/pull/21252) +- Style tweaks to the patterns library sidebar. [21263](https://github.com/WordPress/gutenberg/pull/21263) +- Smaller space between toolbar and block. [21166](https://github.com/WordPress/gutenberg/pull/21166) + +### Performance + +- Add block selection performance test. [21230](https://github.com/WordPress/gutenberg/pull/21230) +- Improve the performance of the block moving animation. [21231](https://github.com/WordPress/gutenberg/pull/21231) +- Render the patterns list asynchronously. [21322](https://github.com/WordPress/gutenberg/pull/21322) + +### Bug Fixes + +- Improve WordPress logo rendering for non-retina displays. [21217](https://github.com/WordPress/gutenberg/pull/21217) +- Fix inserter popover direction. [21556](https://github.com/WordPress/gutenberg/pull/21556) +- Fix Snackbar notice bottom margin. [18858](https://github.com/WordPress/gutenberg/pull/18858) +- Fix YouTube Embed block from flickering and crashing on Safari. [21225](https://github.com/WordPress/gutenberg/pull/21225) +- Fix sibling inserter being unclickable. [21232](https://github.com/WordPress/gutenberg/pull/21232) +- Fix block duplication using keyboard shortcut [21317](https://github.com/WordPress/gutenberg/pull/21317) +- Avoid creating an empty paragraph when selecting the parent's group block [21318](https://github.com/WordPress/gutenberg/pull/21318) +- Fix the Buttons block margins. [21376](https://github.com/WordPress/gutenberg/pull/21376) +- Prevent typing on a Popover from closing the block toolbar [21421](https://github.com/WordPress/gutenberg/pull/21421) +- Prevent copy/paste on number inputs from copying the post content. [21457](https://github.com/WordPress/gutenberg/pull/21457) +- Prevent scroll jumps when focusing long blocks. [21460](https://github.com/WordPress/gutenberg/pull/21460) +- Fix Separator block RTL styles. [21525](https://github.com/WordPress/gutenberg/pull/21525) +- Make dateI18n returns be affected by `gmt` parameter. [18982](https://github.com/WordPress/gutenberg/pull/18982) +- Fixes the read more link added by themes in the Latest Posts block. [20541](https://github.com/WordPress/gutenberg/pull/20541) +- Fix the Latest Posts block when `imageDimensions` is empty [21070](https://github.com/WordPress/gutenberg/pull/21070) +- Fix transparent images used as Cover block backgrounds. [20904](https://github.com/WordPress/gutenberg/pull/20904) +- IE11: fix focus on backspace. [21092](https://github.com/WordPress/gutenberg/pull/21092) +- Fix IE11 breakage when hitting Enter. [21361](https://github.com/WordPress/gutenberg/pull/21361) [21366](https://github.com/WordPress/gutenberg/pull/21366) +- Fix block movers on full-wide blocks. [21097](https://github.com/WordPress/gutenberg/pull/21097) +- Fix Annotations classNames. [21184](https://github.com/WordPress/gutenberg/pull/21184) +- RangeControl: Fix zero value handling with number input. [21187](https://github.com/WordPress/gutenberg/pull/21187) +- Fix reusable block horizontal padding regression. [21312](https://github.com/WordPress/gutenberg/pull/21312) +- Fix fullwide margins regression. [21201](https://github.com/WordPress/gutenberg/pull/21201) +- Prevent the Cover block from overriding the children blocks colors [21254](https://github.com/WordPress/gutenberg/pull/21254) +- Fix overly verbose aria-label in Social Link block [21369](https://github.com/WordPress/gutenberg/pull/21369) +- Fix container block appenders and sibling inserters. [21149](https://github.com/WordPress/gutenberg/pull/21149) [21142](https://github.com/WordPress/gutenberg/pull/21142) [21143](https://github.com/WordPress/gutenberg/pull/21143) + +### New APIs + +- @wordpress/i18n: Add create-i18n function. [21182](https://github.com/WordPress/gutenberg/pull/21182) +- @wordpress/interface: + - Add screen sidebar extensibility APIs. [20698](https://github.com/WordPress/gutenberg/pull/20698) [21260](https://github.com/WordPress/gutenberg/pull/21260) + - Prepare for npm release. [21417](https://github.com/WordPress/gutenberg/pull/21417) + - Add Fullscreen mode component. [21334](https://github.com/WordPress/gutenberg/pull/21334) + - Add InterfaceSkeleton component. [21335](https://github.com/WordPress/gutenberg/pull/21335) +- @wordpress/icons: Add new icons: tablet, mobile, desktop, font, share... [21261](https://github.com/WordPress/gutenberg/pull/21261) [21278](https://github.com/WordPress/gutenberg/pull/21278) +- Support changing the Group block's DOM element. [20218](https://github.com/WordPress/gutenberg/pull/20218) +- Block API: Add new utility to register block types from metadata in PHP [20794](https://github.com/WordPress/gutenberg/pull/20794) +- Add radio option to the ButtonGroup component. [20805](https://github.com/WordPress/gutenberg/pull/20805) + +### Experiments + +- Full site editing and Site Editor screen: + - Use the default post comments template for the Post Comments block. [21012](https://github.com/WordPress/gutenberg/pull/21012) + - Use slug as template part display label.[21161](https://github.com/WordPress/gutenberg/pull/21161) + - Remove duplicate queries fetching template parts [18878](https://github.com/WordPress/gutenberg/pull/18878) + - Preload the edited template to avoid the white page effect. [21214](https://github.com/WordPress/gutenberg/pull/21214) + - Move the menu item to the top level. [21273](https://github.com/WordPress/gutenberg/pull/21273) + - Add block breadcrumb; [21274](https://github.com/WordPress/gutenberg/pull/21274) + - Prevent template switcher jumpiness. [21280](https://github.com/WordPress/gutenberg/pull/21280) + - Increase the viewport width used for template previews. [21287](https://github.com/WordPress/gutenberg/pull/21287) + - Add top level inserter. [21328](https://github.com/WordPress/gutenberg/pull/21328) + - Apply the editor styles. [20982](https://github.com/WordPress/gutenberg/pull/20982) + - Update the multi-entity saving flow UI. [21159](https://github.com/WordPress/gutenberg/pull/21159) + - Small updates to template selector. [21202](https://github.com/WordPress/gutenberg/pull/21202) +- New navigation screen: + - Bootstrap the screen. [21036](https://github.com/WordPress/gutenberg/pull/21036) + - Implement the initial styling. [21314](https://github.com/WordPress/gutenberg/pull/21314) + - Add save shortcut. [21342](https://github.com/WordPress/gutenberg/pull/21342) + - Fix editor shortcuts. [21338](https://github.com/WordPress/gutenberg/pull/21338) + - Basic responsive styles. [21414](https://github.com/WordPress/gutenberg/pull/21414) +- Navigation block: + - Make the submenus usable on mobile. [21471](https://github.com/WordPress/gutenberg/pull/21471) + - Fix block for contributor users [18669](https://github.com/WordPress/gutenberg/pull/18669) + - Fix submenus being overlapped by wrapping top-level nav links. [21140](https://github.com/WordPress/gutenberg/pull/21140) + - Add vertical variation. [21296](https://github.com/WordPress/gutenberg/pull/21296) + - Show color controls in toolbar only. [20884](https://github.com/WordPress/gutenberg/pull/20884) + - Add capture toolbars prop to inner blocks. [21095](https://github.com/WordPress/gutenberg/pull/21095) +- Block API Support flags: + - Introduce a support key for support global style colors in blocks. [21021](https://github.com/WordPress/gutenberg/pull/21021) [21428](https://github.com/WordPress/gutenberg/pull/21428) + - Add the possibility to support gradients using the experimental color support flag; [21481](https://github.com/WordPress/gutenberg/pull/21481) + - Add a block support flag for font size. [21153](https://github.com/WordPress/gutenberg/pull/21153) +- Remove experimentalUIParts API. [20979](https://github.com/WordPress/gutenberg/pull/20979) +- Add experimental Text component. [21088](https://github.com/WordPress/gutenberg/pull/21088) + +### Documentation + +- Docs: Describe tools used in E2E testing. [21295](https://github.com/WordPress/gutenberg/pull/21295) +- WP-env: Add reference to docker log command to show error logs in terminal. [21308](https://github.com/WordPress/gutenberg/pull/21308) +- Docs: Add section in block RFC about register_block_type_from_metadata. [21501](https://github.com/WordPress/gutenberg/pull/21501) +- Update serverSideRender docs to include how to use from the wp global. [18722](https://github.com/WordPress/gutenberg/pull/18722) +- Prescribe latest NPM for development environment. [21017](https://github.com/WordPress/gutenberg/pull/21017) +- Update Documentation on how to update post meta values from a block. [21155](https://github.com/WordPress/gutenberg/pull/21155) +- Document getAnchorRect prop for Popover component. [17709](https://github.com/WordPress/gutenberg/pull/17709) +- Typos and tweaks: [21228](https://github.com/WordPress/gutenberg/pull/21228), [21364](https://github.com/WordPress/gutenberg/pull/21364), [21405](https://github.com/WordPress/gutenberg/pull/21405), [20660](https://github.com/WordPress/gutenberg/pull/20660), [21297](https://github.com/WordPress/gutenberg/pull/21297). + +### Code Quality + +- Add types to WordPress packages: + - @wordpress/element [21248](https://github.com/WordPress/gutenberg/pull/21248) + - @wordpress/primitives [21482](https://github.com/WordPress/gutenberg/pull/21482) + - @wordpress/icons [21487](https://github.com/WordPress/gutenberg/pull/21487) + - @wordpress/autop, @wordpress/escape-html and @wordpress/html-entities [20669](https://github.com/WordPress/gutenberg/pull/20669) + - @wordpress/i18n [21224](https://github.com/WordPress/gutenberg/pull/21224) + - @wordpress/prettier-config [21381](https://github.com/WordPress/gutenberg/pull/21381) [21053](https://github.com/WordPress/gutenberg/pull/21053) + - @wordpress/block-editor DOM utils. [21362](https://github.com/WordPress/gutenberg/pull/21362) +- Update the Buttons block to use the new color support flag. [21266](https://github.com/WordPress/gutenberg/pull/21266) +- Update the Paragraph block to use the colors support flag. [21037](https://github.com/WordPress/gutenberg/pull/21037) +- Update the Columns block to use the colors support flag. [21038](https://github.com/WordPress/gutenberg/pull/21038) +- Update the Heading block to use the colors support flag. [21039](https://github.com/WordPress/gutenberg/pull/21039) +- Update the Media & Text block to use the colors support flag. [21169](https://github.com/WordPress/gutenberg/pull/21169) +- Refactor env commands into separate files .[21353](https://github.com/WordPress/gutenberg/pull/21353) +- Remove the deprecated `request` dependency. [21398](https://github.com/WordPress/gutenberg/pull/21398) +- Move default styles to editor normalisation stylesheet. [19837](https://github.com/WordPress/gutenberg/pull/19837) +- Replace lodash.assign with vanilla JS. [21054](https://github.com/WordPress/gutenberg/pull/21054) +- Remove the old block preview implementation. [21096](https://github.com/WordPress/gutenberg/pull/21096) +- Make RichText window/document agnostic. [21105](https://github.com/WordPress/gutenberg/pull/21105) +- Polish a11y package. [21148](https://github.com/WordPress/gutenberg/pull/21148) +- Fix two typos in lib rest menu controller. [21418](https://github.com/WordPress/gutenberg/pull/21418) +- Global tips: Add period at the end of sentence. [20601](https://github.com/WordPress/gutenberg/pull/20601) +- Lighter block DOM: + - Verse block [20752](https://github.com/WordPress/gutenberg/pull/20752) + - Code block [21079](https://github.com/WordPress/gutenberg/pull/21079) + - Preformatted block [21146](https://github.com/WordPress/gutenberg/pull/21146) +- Update the padding values on the Card component to align with proposed spacing system. [21111](https://github.com/WordPress/gutenberg/pull/21111) +- Disable scroll in PlainText component. [21115](https://github.com/WordPress/gutenberg/pull/21115) +- Simplify inserter hasItems check. [21138](https://github.com/WordPress/gutenberg/pull/21138) +- Avoid string concatenation for the Latest Post block read more link. [21170](https://github.com/WordPress/gutenberg/pull/21170) + +### Various + +- Plugin: Bump tested up to info to WP 5.4 [21400](https://github.com/WordPress/gutenberg/pull/21400) +- Output package type declarations. [18942](https://github.com/WordPress/gutenberg/pull/18942) +- Exclude native files from type checking. [21491](https://github.com/WordPress/gutenberg/pull/21491) +- docgen: Optimize README update script. [18840](https://github.com/WordPress/gutenberg/pull/18840) +- Check Latest NPM on npm install. [21521](https://github.com/WordPress/gutenberg/pull/21521) +- E2E Tests: + - Improve stability of image block test [21174](https://github.com/WordPress/gutenberg/pull/21174) + - Improve Allowed Inner Blocks test stability [21175](https://github.com/WordPress/gutenberg/pull/21175) + - Use waitForSelector to wait for sidebar presence [21180](https://github.com/WordPress/gutenberg/pull/21180) +- Unit Tests: + - Fix @wordpress/env testPortNumberValidation unit test. [21394](https://github.com/WordPress/gutenberg/pull/21394) + - Introduce react-testing-library to some existing unit tests. [20428](https://github.com/WordPress/gutenberg/pull/20428) + - Components: Add SlotFill test. [21226](https://github.com/WordPress/gutenberg/pull/21226) + - Fail E2E when page displays warning notices [13452](https://github.com/WordPress/gutenberg/pull/13452) +- Project Management: Prompt user to link GitHub account to WordPress.org profile [21221](https://github.com/WordPress/gutenberg/pull/21221) [21384](https://github.com/WordPress/gutenberg/pull/21384) +- @wordpress/env: Bind "core" files to tests environment [21195](https://github.com/WordPress/gutenberg/pull/21195) +- ESLint Plugin: Continue considering unused variables after encountering exception [21354](https://github.com/WordPress/gutenberg/pull/21354) +- Enable prettier for JSX files [21151](https://github.com/WordPress/gutenberg/pull/21151) +- Increase severity of JSDoc linting to error. [20427](https://github.com/WordPress/gutenberg/pull/20427) +- Add I18N specific ESLint rules. [20555](https://github.com/WordPress/gutenberg/pull/20555) [20574](https://github.com/WordPress/gutenberg/pull/20574) +- Update uuid to v7.0.2. [21258](https://github.com/WordPress/gutenberg/pull/21258) +- Upgrade Reakit to version 1.0.0-rc.0; [21300](https://github.com/WordPress/gutenberg/pull/21300) +- Framework: Add package-lock precommit check for latest NPM. [21306](https://github.com/WordPress/gutenberg/pull/21306) +- Babel Preset: Update Babel version to 7.9.x. [21419](https://github.com/WordPress/gutenberg/pull/21419) +- ESLint Plugin: Update ESLint and related dependencies to 6.8.x. [21424](https://github.com/WordPress/gutenberg/pull/21424) +- Framework: Configure ESLint JSDoc plugin to target TypeScript mode. [18998](https://github.com/WordPress/gutenberg/pull/18998) +- Major version upgrade for Jest in all packages. [20766](https://github.com/WordPress/gutenberg/pull/20766) +- Storybook: + - Add TreeSelect component. [20496](https://github.com/WordPress/gutenberg/pull/20496) + - Update AnglePickerControl title. [21089](https://github.com/WordPress/gutenberg/pull/21089) +- Automated Testing: composer non-interactive flag for Travis. [21118](https://github.com/WordPress/gutenberg/pull/21118) +- REST API error message: Remove unnecessary space. [21178](https://github.com/WordPress/gutenberg/pull/21178) +- SlotFill: Guard property access to possibly-undefined slot. [21205](https://github.com/WordPress/gutenberg/pull/21205) +- Build: Add TypeScript version validation [21208](https://github.com/WordPress/gutenberg/pull/21208) + + + += 7.8.1 = + + + += 7.8.0 = + +## Enhancements +​ +- Add visible labels to BlockPatternPicker pattern selection buttons [19789](https://github.com/WordPress/gutenberg/pull/19789) +- Adds always on display of media URL [19504](https://github.com/WordPress/gutenberg/pull/19504) +- Adds current menu class to navigation block [20076](https://github.com/WordPress/gutenberg/pull/20076) +- Block: Outline when interacting with Toolbar Block Type/Movers [20938](https://github.com/WordPress/gutenberg/pull/20938) +- Create block: Improve how prompts and values provided are handled [20756](https://github.com/WordPress/gutenberg/pull/20756) +- Expand create block options and add readme.txt template [20694](https://github.com/WordPress/gutenberg/pull/20694) +- Patterns: Make adding patterns easier [20854](https://github.com/WordPress/gutenberg/pull/20854) +- Polish a few icons [20980](https://github.com/WordPress/gutenberg/pull/20980) +- Polish date-picker component [20824](https://github.com/WordPress/gutenberg/pull/20824) +- Improve permalink editing [12009](https://github.com/WordPress/gutenberg/pull/12009) +- Nicer block footprint for social links [20978](https://github.com/WordPress/gutenberg/pull/20978) +- Show inserter only when block selected for nesting contexts [20753](https://github.com/WordPress/gutenberg/pull/20753) +- URL: Use test data from web-platform-tests for isURL spec conformance [20537](https://github.com/WordPress/gutenberg/pull/20537) +- Adds multi-select to categories on Latest Posts [20781](https://github.com/WordPress/gutenberg/pull/20781) +- Add basic nav block example for inserter and styles previews [21011](https://github.com/WordPress/gutenberg/pull/21011) +​ +## Bug Fixes +​ +- Allow media library in gallery mode to be reset [20675](https://github.com/WordPress/gutenberg/pull/20675) +- Autocomplete: Add support for results with long titles [20962](https://github.com/WordPress/gutenberg/pull/20962) +- Compat: Conditionally filter editor settings for image dimensions [20939](https://github.com/WordPress/gutenberg/pull/20939) +- Compat: Use core-js-url-browser for URL polyfill [20225](https://github.com/WordPress/gutenberg/pull/20225) +- Data: Migrate post editor persistence with fullscreenMode false [21082](https://github.com/WordPress/gutenberg/pull/21082) +- Edit Post: Make sidebar header focusable for button focus normalization [21031](https://github.com/WordPress/gutenberg/pull/21031) +- Fix auto-hiding appender regression [20780](https://github.com/WordPress/gutenberg/pull/20780) +- Fix fullscreen mode device preview [21010](https://github.com/WordPress/gutenberg/pull/21010) +- Fix link control search results spacing. [21003](https://github.com/WordPress/gutenberg/pull/21003) +- Fix snackbar container block portion of UI while present [21000](https://github.com/WordPress/gutenberg/pull/21000) +- Make the inner button block not allowed as a reusable block or editable as HTML [20948](https://github.com/WordPress/gutenberg/pull/20948) +- URL: Fix getQueryString incorrect handling of hash fragment [20738](https://github.com/WordPress/gutenberg/pull/20738) +- Update social links block to output a custom class on each individual link [20998](https://github.com/WordPress/gutenberg/pull/20998) +- Update the inserter's block preview to use the AutoHeightPreview [20817](https://github.com/WordPress/gutenberg/pull/20817) +- Latest Posts: + - Fix link for read more markup [20917](https://github.com/WordPress/gutenberg/pull/20917) + - Fixes the categories selector crash when category does not exist [20960](https://github.com/WordPress/gutenberg/pull/20960) +- Fix input rules [20964](https://github.com/WordPress/gutenberg/pull/20964) +- Trim input value in navigation search input field [19832](https://github.com/WordPress/gutenberg/pull/19832) +- Fix mobile header [20946](https://github.com/WordPress/gutenberg/pull/20946) +- Fix visually hidden classnames [20649](https://github.com/WordPress/gutenberg/pull/20649) +- Fix/screen reader text [20607](https://github.com/WordPress/gutenberg/pull/20607) +- Fix SelectControl example code synax highlight [19803](https://github.com/WordPress/gutenberg/pull/19803) +​ +## New APIs +​ +- Add initial API to register patterns from themes and plugins [21074](https://github.com/WordPress/gutenberg/pull/21074) +- Convert \__experimentalCreateInterpolateElement to a stable API [20699](https://github.com/WordPress/gutenberg/pull/20699) +​ +## Experiments +​ +- Site Editor: + - Add Fullscreen mode [20691](https://github.com/WordPress/gutenberg/pull/20691) + - Add fullscreen close button [20989](https://github.com/WordPress/gutenberg/pull/20989) + - Add more menu and fullscreen toggle [21006](https://github.com/WordPress/gutenberg/pull/21006) + - Style resets for top level page [20886](https://github.com/WordPress/gutenberg/pull/20886) + - Get current template part correctly for auto drafts [20438](https://github.com/WordPress/gutenberg/pull/20438) + - Add template preview to the edit site template switcher [20958](https://github.com/WordPress/gutenberg/pull/20958) + - Add things required to load custom blocks to Site Editor page [20549](https://github.com/WordPress/gutenberg/pull/20549) + - Avoid page templates overwriting page title [20865](https://github.com/WordPress/gutenberg/pull/20865) +- Lighter block DOM: + - Group [20586](https://github.com/WordPress/gutenberg/pull/20586) + - Navigation [20729](https://github.com/WordPress/gutenberg/pull/20729) +- Navigation Block: + - Fix dynamic rendering recursive function name typo [21078](https://github.com/WordPress/gutenberg/pull/21078) + - Avoid hiding submenu when adding a link [21035](https://github.com/WordPress/gutenberg/pull/21035) + - Fix toolbar overlap on navigation links [21033](https://github.com/WordPress/gutenberg/pull/21033) +- PlainText v2 [21076](https://github.com/WordPress/gutenberg/pull/21076) + - Editable Component [18361](https://github.com/WordPress/gutenberg/pull/18361) +​ +## Documentation +​ +- Add ESNext example for unregisterBlockType [20784](https://github.com/WordPress/gutenberg/pull/20784) +- Docs/SlotFills: Small update for consistency [20767](https://github.com/WordPress/gutenberg/pull/20767) +- Correct 2nd param of useViewportMatch() usage [20911](https://github.com/WordPress/gutenberg/pull/20911) +- Include `npm run dev` guidance in "Getting Started" [21015](https://github.com/WordPress/gutenberg/pull/21015) +- Document default login credentials and `wp-env run` command [20678](https://github.com/WordPress/gutenberg/pull/20678) +- Fixes docblock for useViewportMatch [20919](https://github.com/WordPress/gutenberg/pull/20919) +- Lowercase visual editor and code editor to match block editor and classic editor [20968](https://github.com/WordPress/gutenberg/pull/20968) +- Update README.md [20913](https://github.com/WordPress/gutenberg/pull/20913) +- Add Custom Block Editor to TOC and Manifest [20749](https://github.com/WordPress/gutenberg/pull/20749) +- Add tutorial link to Table of Contents for Custom Block Editor [20750](https://github.com/WordPress/gutenberg/pull/20750) +​ +## Code Quality +​ +- Block Editor: Use useResizeObserver in place of direct react-resize-aware dependency [20889](https://github.com/WordPress/gutenberg/pull/20889) +- E2E Test Utils: Improve durability of embedding matcher [20811](https://github.com/WordPress/gutenberg/pull/20811) +- Framework: Migrate/remove temporary compatibility script initialization [19178](https://github.com/WordPress/gutenberg/pull/19178) +- Framework: Use WHATWG URL in place of legacy url module [19823](https://github.com/WordPress/gutenberg/pull/19823) +- Nav Block: Remove 'frontend' from style comments [21034](https://github.com/WordPress/gutenberg/pull/21034) +- Project Management Automation: Add TypeScript type-checking [20850](https://github.com/WordPress/gutenberg/pull/20850) +- Refactor the inserter menu component and split into multiple smaller components [20880](https://github.com/WordPress/gutenberg/pull/20880) +- Remove iframe from content elements [20976](https://github.com/WordPress/gutenberg/pull/20976) +- Update Search/RSS block render method [20977](https://github.com/WordPress/gutenberg/pull/20977) +​ +## Various +​ +- Update glossary [20934](https://github.com/WordPress/gutenberg/pull/20934) +- Improve performance testing [20802](https://github.com/WordPress/gutenberg/pull/20802) +- Edit Post: Register block patterns as separate plugin [20871](https://github.com/WordPress/gutenberg/pull/20871) +- Accessibility: updated headings to reflect semantic relationship between html tag and it's content. [16444](https://github.com/WordPress/gutenberg/pull/16444) +- Add Prettier shared config package [20026](https://github.com/WordPress/gutenberg/pull/20026) +- Add default styles to the TabPanel component [20872](https://github.com/WordPress/gutenberg/pull/20872) +- Add isFileURL method and use it on all native media upload checks. [20985](https://github.com/WordPress/gutenberg/pull/20985) +- Add menus endpoints. [20292](https://github.com/WordPress/gutenberg/pull/20292) +- Block Patterns: Update text-two-columns.json [20890](https://github.com/WordPress/gutenberg/pull/20890) +- Block Styles: Remove the block margin in the style selector [19983](https://github.com/WordPress/gutenberg/pull/19983) +- Block patterns: improve success notice [21005](https://github.com/WordPress/gutenberg/pull/21005) +- Blocks: Allow the Default Style selector to be hidden. [20620](https://github.com/WordPress/gutenberg/pull/20620) +- E2E Tests: Mock Embed response for InnerBlocks locking test [20481](https://github.com/WordPress/gutenberg/pull/20481) +- ESLint Plugin: Relax `prefer-const` for destructuring assignment [20737](https://github.com/WordPress/gutenberg/pull/20737) +- Gallery: Update UI of controls [20776](https://github.com/WordPress/gutenberg/pull/20776) +- Improves RTL style conversion [20503](https://github.com/WordPress/gutenberg/pull/20503) +- Minor change to switch Help link target to _blank, add rels [20800](https://github.com/WordPress/gutenberg/pull/20800) +- Mobile: Add accessibility label to Block List Footer [20633](https://github.com/WordPress/gutenberg/pull/20633) +- Moves category multi select from LatestPosts to QueryControls [20832](https://github.com/WordPress/gutenberg/pull/20832) +- Paste: replace iframes with url [20983](https://github.com/WordPress/gutenberg/pull/20983) +- Polish poster image button arrangement. [20754](https://github.com/WordPress/gutenberg/pull/20754) +- Preview Button: Remove the separator and border, and reduce the size of the icon. [20683](https://github.com/WordPress/gutenberg/pull/20683) +- RangeControl: Improve disabled rendering and interactions [20723](https://github.com/WordPress/gutenberg/pull/20723) +- Reduce gap between block library and preview [20777](https://github.com/WordPress/gutenberg/pull/20777) +- Remove aria-expanded from close button in Publish panel [20993](https://github.com/WordPress/gutenberg/pull/20993) +- Remove feature flag for mobile page templates [20718](https://github.com/WordPress/gutenberg/pull/20718) +- Remove inaccurate message from image block [20909](https://github.com/WordPress/gutenberg/pull/20909) +- Removed the textarea width restriction for the Shortcode block [20624](https://github.com/WordPress/gutenberg/pull/20624) +- Revert "Framework: Travis: Avoid skipping Puppeteer download" [20828](https://github.com/WordPress/gutenberg/pull/20828) +- Show errors in the media replace control [19244](https://github.com/WordPress/gutenberg/pull/19244) +- Styles Panel: Don't force it to be closed by default. [20617](https://github.com/WordPress/gutenberg/pull/20617) +- Update Navigation Menu Item icon [20763](https://github.com/WordPress/gutenberg/pull/20763) +- Update page template picker after design review [20883](https://github.com/WordPress/gutenberg/pull/20883) +- Latest Posts: Testing larger margins [20563](https://github.com/WordPress/gutenberg/pull/20563) +- Add codeowners for env package [20667](https://github.com/WordPress/gutenberg/pull/20667) +- Scripts: Update all webpack related dependencies [20916](https://github.com/WordPress/gutenberg/pull/20916) +- Dependencies webpack plugin: Let the output file be specified when output is combined [20844](https://github.com/WordPress/gutenberg/pull/20844) + = 7.7.1 = ### Bug Fixes diff --git a/composer.json b/composer.json index 3d3098abaff758..f94b3c18e89fd6 100644 --- a/composer.json +++ b/composer.json @@ -11,11 +11,11 @@ "issues": "https://github.com/WordPress/gutenberg/issues" }, "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0", - "squizlabs/php_codesniffer": "^3.4.2", - "phpcompatibility/php-compatibility": "^9.2.0", - "wp-coding-standards/wpcs": "^2.1.1", - "sirbrillig/phpcs-variable-analysis": "^2.7" + "dealerdirect/phpcodesniffer-composer-installer": "^0.6", + "squizlabs/php_codesniffer": "^3.5", + "phpcompatibility/php-compatibility": "^9.3", + "wp-coding-standards/wpcs": "^2.2", + "sirbrillig/phpcs-variable-analysis": "^2.8" }, "require": { "composer/installers": "~1.0" diff --git a/composer.lock b/composer.lock index 594d8bb48c929d..3ac63fed05df15 100644 --- a/composer.lock +++ b/composer.lock @@ -1,35 +1,38 @@ { "_readme": [ "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f802871495ce4d7ed5928e17524d0cdb", + "content-hash": "9745a2b1c8d1005bf9f7617061e4fc7d", "packages": [ { "name": "composer/installers", - "version": "v1.6.0", + "version": "v1.9.0", "source": { "type": "git", "url": "https://github.com/composer/installers.git", - "reference": "cfcca6b1b60bc4974324efb5783c13dca6932b5b" + "reference": "b93bcf0fa1fccb0b7d176b0967d969691cd74cca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/installers/zipball/cfcca6b1b60bc4974324efb5783c13dca6932b5b", - "reference": "cfcca6b1b60bc4974324efb5783c13dca6932b5b", + "url": "https://api.github.com/repos/composer/installers/zipball/b93bcf0fa1fccb0b7d176b0967d969691cd74cca", + "reference": "b93bcf0fa1fccb0b7d176b0967d969691cd74cca", "shasum": "" }, "require": { - "composer-plugin-api": "^1.0" + "composer-plugin-api": "^1.0 || ^2.0" }, "replace": { "roundcube/plugin-installer": "*", "shama/baton": "*" }, "require-dev": { - "composer/composer": "1.0.*@dev", - "phpunit/phpunit": "^4.8.36" + "composer/composer": "1.6.* || 2.0.*@dev", + "composer/semver": "1.0.* || 2.0.*@dev", + "phpunit/phpunit": "^4.8.36", + "sebastian/comparator": "^1.2.4", + "symfony/process": "^2.3" }, "type": "composer-plugin", "extra": { @@ -65,6 +68,7 @@ "Kanboard", "Lan Management System", "MODX Evo", + "MantisBT", "Mautic", "Maya", "OXID", @@ -73,6 +77,7 @@ "RadPHP", "SMF", "Thelia", + "Whmcs", "WolfCMS", "agl", "aimeos", @@ -95,6 +100,7 @@ "installer", "itop", "joomla", + "known", "kohana", "laravel", "lavalite", @@ -117,6 +123,7 @@ "shopware", "silverstripe", "sydes", + "sylius", "symfony", "typo3", "wordpress", @@ -124,22 +131,22 @@ "zend", "zikula" ], - "time": "2018-08-27T06:10:37+00:00" + "time": "2020-04-07T06:57:05+00:00" } ], "packages-dev": [ { "name": "dealerdirect/phpcodesniffer-composer-installer", - "version": "v0.5.0", + "version": "v0.6.2", "source": { "type": "git", "url": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer.git", - "reference": "e749410375ff6fb7a040a68878c656c2e610b132" + "reference": "8001af8eb107fbfcedc31a8b51e20b07d85b457a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/e749410375ff6fb7a040a68878c656c2e610b132", - "reference": "e749410375ff6fb7a040a68878c656c2e610b132", + "url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/8001af8eb107fbfcedc31a8b51e20b07d85b457a", + "reference": "8001af8eb107fbfcedc31a8b51e20b07d85b457a", "shasum": "" }, "require": { @@ -192,20 +199,20 @@ "stylecheck", "tests" ], - "time": "2018-10-26T13:21:45+00:00" + "time": "2020-01-29T20:22:20+00:00" }, { "name": "phpcompatibility/php-compatibility", - "version": "9.2.0", + "version": "9.3.5", "source": { "type": "git", "url": "https://github.com/PHPCompatibility/PHPCompatibility.git", - "reference": "3db1bf1e28123fd574a4ae2e9a84072826d51b5e" + "reference": "9fb324479acf6f39452e0655d2429cc0d3914243" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibility/zipball/3db1bf1e28123fd574a4ae2e9a84072826d51b5e", - "reference": "3db1bf1e28123fd574a4ae2e9a84072826d51b5e", + "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibility/zipball/9fb324479acf6f39452e0655d2429cc0d3914243", + "reference": "9fb324479acf6f39452e0655d2429cc0d3914243", "shasum": "" }, "require": { @@ -228,10 +235,6 @@ "LGPL-3.0-or-later" ], "authors": [ - { - "name": "Contributors", - "homepage": "https://github.com/PHPCompatibility/PHPCompatibility/graphs/contributors" - }, { "name": "Wim Godden", "homepage": "https://github.com/wimg", @@ -241,6 +244,10 @@ "name": "Juliette Reinders Folmer", "homepage": "https://github.com/jrfnl", "role": "lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCompatibility/PHPCompatibility/graphs/contributors" } ], "description": "A set of sniffs for PHP_CodeSniffer that checks for PHP cross-version compatibility.", @@ -250,32 +257,32 @@ "phpcs", "standards" ], - "time": "2019-06-27T19:58:56+00:00" + "time": "2019-12-27T09:44:58+00:00" }, { "name": "sirbrillig/phpcs-variable-analysis", - "version": "v2.7.0", + "version": "v2.8.1", "source": { "type": "git", "url": "https://github.com/sirbrillig/phpcs-variable-analysis.git", - "reference": "1b1b2b503a19bb56fa75f4a2d959b12c8ed28c12" + "reference": "5be26b4d719acaf7a433d1cad469159cbf034f2a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sirbrillig/phpcs-variable-analysis/zipball/1b1b2b503a19bb56fa75f4a2d959b12c8ed28c12", - "reference": "1b1b2b503a19bb56fa75f4a2d959b12c8ed28c12", + "url": "https://api.github.com/repos/sirbrillig/phpcs-variable-analysis/zipball/5be26b4d719acaf7a433d1cad469159cbf034f2a", + "reference": "5be26b4d719acaf7a433d1cad469159cbf034f2a", "shasum": "" }, "require": { - "php": ">=5.6.0" + "php": ">=5.6.0", + "squizlabs/php_codesniffer": "^3.1" }, "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.4.4", + "dealerdirect/phpcodesniffer-composer-installer": "^0.4.4 || ^0.5 || ^0.6", "limedeck/phpunit-detailed-printer": "^3.1", "phpstan/phpstan": "^0.11.8", - "phpunit/phpunit": "^6.5", - "sirbrillig/phpcs-import-detection": "^1.1", - "squizlabs/php_codesniffer": "^3.1" + "phpunit/phpunit": "^5.0 || ^6.5", + "sirbrillig/phpcs-import-detection": "^1.1" }, "type": "phpcodesniffer-standard", "autoload": { @@ -288,30 +295,30 @@ "BSD-2-Clause" ], "authors": [ - { - "name": "Payton Swick", - "email": "payton@foolord.com" - }, { "name": "Sam Graham", "email": "php-codesniffer-variableanalysis@illusori.co.uk" + }, + { + "name": "Payton Swick", + "email": "payton@foolord.com" } ], "description": "A PHPCS sniff to detect problems with variables.", - "time": "2019-06-24T23:57:11+00:00" + "time": "2020-02-11T22:18:48+00:00" }, { "name": "squizlabs/php_codesniffer", - "version": "3.4.2", + "version": "3.5.5", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "b8a7362af1cc1aadb5bd36c3defc4dda2cf5f0a8" + "reference": "73e2e7f57d958e7228fce50dc0c61f58f017f9f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/b8a7362af1cc1aadb5bd36c3defc4dda2cf5f0a8", - "reference": "b8a7362af1cc1aadb5bd36c3defc4dda2cf5f0a8", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/73e2e7f57d958e7228fce50dc0c61f58f017f9f6", + "reference": "73e2e7f57d958e7228fce50dc0c61f58f017f9f6", "shasum": "" }, "require": { @@ -349,20 +356,20 @@ "phpcs", "standards" ], - "time": "2019-04-10T23:49:02+00:00" + "time": "2020-04-17T01:09:41+00:00" }, { "name": "wp-coding-standards/wpcs", - "version": "2.1.1", + "version": "2.2.1", "source": { "type": "git", "url": "https://github.com/WordPress/WordPress-Coding-Standards.git", - "reference": "bd9c33152115e6741e3510ff7189605b35167908" + "reference": "b5a453203114cc2284b1a614c4953456fbe4f546" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/bd9c33152115e6741e3510ff7189605b35167908", - "reference": "bd9c33152115e6741e3510ff7189605b35167908", + "url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/b5a453203114cc2284b1a614c4953456fbe4f546", + "reference": "b5a453203114cc2284b1a614c4953456fbe4f546", "shasum": "" }, "require": { @@ -370,12 +377,12 @@ "squizlabs/php_codesniffer": "^3.3.1" }, "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0", + "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || ^0.6", "phpcompatibility/php-compatibility": "^9.0", "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" }, "suggest": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically." + "dealerdirect/phpcodesniffer-composer-installer": "^0.6 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically." }, "type": "phpcodesniffer-standard", "notification-url": "https://packagist.org/downloads/", @@ -385,7 +392,7 @@ "authors": [ { "name": "Contributors", - "homepage": "https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards/graphs/contributors" + "homepage": "https://github.com/WordPress/WordPress-Coding-Standards/graphs/contributors" } ], "description": "PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions", @@ -394,7 +401,7 @@ "standards", "wordpress" ], - "time": "2019-05-21T02:50:00+00:00" + "time": "2020-02-04T02:52:06+00:00" } ], "aliases": [], diff --git a/docs/contributors/coding-guidelines.md b/docs/contributors/coding-guidelines.md index a8f0698fa4a5c2..ba904db9cc9226 100644 --- a/docs/contributors/coding-guidelines.md +++ b/docs/contributors/coding-guidelines.md @@ -216,7 +216,7 @@ Custom types should be named as succinctly as possible, while still retaining cl /** * A block selection object. * - * @typedef {Object} WPBlockSelection + * @typedef WPBlockSelection * * @property {string} clientId A block client ID. * @property {string} attributeKey A block attribute key. @@ -225,6 +225,8 @@ Custom types should be named as succinctly as possible, while still retaining cl */ ``` +Note that there is no `{Object}` between `@typedef` and the type name. As `@property`s below tells us that it is a type for objects, it is recommend to not use `{Object}` when you want to define types for your objects. + Custom types can also be used to describe a set of predefined options. While the [type union](https://jsdoc.app/tags-type.html) can be used with literal values as an inline type, it can be difficult to align tags while still respecting a maximum line length of 80 characters. Using a custom type to define a union type can afford the opportunity to describe the purpose of these options, and helps to avoid these line length issues. ```js @@ -269,24 +271,26 @@ If you use a [TypeScript integration](https://github.com/Microsoft/TypeScript/wi For packages which do not distribute their own TypeScript types, you are welcomed to install and use the [DefinitelyTyped](http://definitelytyped.org/) community-maintained types definitions, if one exists. -### Record Types +### Generic Types When documenting a generic type such as `Object`, `Function`, `Promise`, etc., always include details about the expected record types. ```js -// Incorrect: +// Bad: /** @type {Object} */ /** @type {Function} */ /** @type {Promise} */ -// Correct: +// Good: -/** @type {Object} */ +/** @type {Record} */ /* or */ /** @type {{[setting:string]:any}} */ /** @type {(key:string)=>boolean} */ /** @type {Promise} */ ``` +When an object is used as a dictionary, you can define its type in 2 ways: indexable interface (`{[setting:string]:any}`) or `Record`. When the name of the key for an object provides hints for developers what to do like `setting`, use indexable interface. If not, use `Record`. + The function expression here uses TypeScript's syntax for function types, which can be useful in providing more detailed information about the names and types of the expected parameters. For more information, consult the [TypeScript `@type` tag function recommendations](https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html#type). In more advanced cases, you may define your own custom types as a generic type using the [TypeScript `@template` tag](https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html#template). @@ -312,7 +316,7 @@ Similar to the "Custom Types" advice concerning type unions and with literal val /** * Hash of breakpoint names with pixel width at which it becomes effective. * - * @type {Object} + * @type {Record} */ const BREAKPOINTS = { huge: 1440 /* , ... */ }; ``` @@ -409,7 +413,7 @@ When documenting an example, use the markdown \`\`\` code block to * select( 'my-shop' ).getPrice( 'hammer' ); * ``` * - * @return {Object} Object containing the store's + * @return {Record} Object containing the store's * selectors. */ ```` diff --git a/docs/contributors/getting-started.md b/docs/contributors/getting-started.md index 1a5656887b3601..a4414814ed3491 100644 --- a/docs/contributors/getting-started.md +++ b/docs/contributors/getting-started.md @@ -2,7 +2,7 @@ Gutenberg is a Node.js-based project, built primarily in JavaScript. -The first step is to install the [latest active LTS release](https://github.com/nodejs/Release#release-schedule) of Node. The easiest way (on macOS, Linux, or Windows 10 with the Linux Subsystem) is by installing and running [nvm]. Once `nvm` is installed, you can install the correct version of Node by running `nvm install` in the Gutenberg directory. +The first step is to install the [latest active LTS release](https://github.com/nodejs/Release#release-schedule) of Node, along with the latest version of [NPM](https://www.npmjs.com/). The easiest way (on macOS, Linux, or Windows 10 with the Linux Subsystem) is by installing and running [nvm]. Once `nvm` is installed, you can install the correct version of Node by running `nvm install --latest-npm` in the Gutenberg directory. Once you have Node installed, run these scripts from within your local Gutenberg repository: @@ -15,6 +15,8 @@ npm run build This will build Gutenberg, ready to be used as a WordPress plugin! +`npm run build` is intended for one-off compilations of the project. If you're planning to do continued development in the source files, using `npm run dev` will most often be the better option. This will configure the build to avoid minifying the generated output, rebuild files automatically as they are changed in your working directory, and configure dependencies as running in a development environment so that useful warnings and errors are logged to your browser's developer console. + If you don't have a local WordPress environment to load Gutenberg in, we can help get that up and running, too. ## Local Environment @@ -54,9 +56,13 @@ See the [relevant section in `wp-env` docs](https://github.com/WordPress/gutenbe ## On A Remote Server -Open a terminal (or if on Windows, a command prompt) and navigate to the repository you cloned. Now type `npm install` to get the dependencies all set up. Once that finishes, you can type `npm run build`. You can now upload the entire repository to your `wp-content/plugins` directory on your web server and activate the plugin from the WordPress admin. +You can use a remote server in development by building locally and then uploading the built files as a plugin to the remote server. + +To build: open a terminal (or if on Windows, a command prompt) and navigate to the repository you cloned. Now type `npm install` to get the dependencies all set up. Once that finishes, you can type `npm run build`. + +After building the cloned gutenberg directory contains the complete plugin, you can upload the entire repository to your `wp-content/plugins` directory and activate the plugin from the WordPress admin. -You can also type `npm run package-plugin` which will run the two commands above and create a zip file automatically for you which you can use to install Gutenberg through the WordPress admin. +Another way to upload after building is to run `npm run package-plugin` to create a plugin zip file β€” this requires `bash` and `php` to run. The script creates `gutenberg.zip` that you can use to install Gutenberg through the WordPress admin. [npm]: https://www.npmjs.com/ [nvm]: https://github.com/creationix/nvm diff --git a/docs/contributors/managing-packages.md b/docs/contributors/managing-packages.md index 7b38b811054c85..9032af8cf3acbe 100644 --- a/docs/contributors/managing-packages.md +++ b/docs/contributors/managing-packages.md @@ -1,8 +1,8 @@ # Managing Packages -This repository uses [lerna] to manage Gutenberg modules and publish them as packages to [npm]. This enforces certain steps in the workflow which are described in details in [packages](/packages/README.md) documentation. +This repository uses [lerna] to manage Gutenberg modules and publish them as packages to [npm]. This enforces certain steps in the workflow which are described in details in [packages](https://github.com/WordPress/gutenberg/blob/master/packages/README.md) documentation. -Maintaining dozens of npm packages is difficultβ€”it can be tough to keep track of changes. That's why we use `CHANGELOG.md` files for each package to simplify the release process. As a contributor, you should add an entry to the aforementioned file each time you contribute adding production code as described in [Maintaining Changelogs](/packages/README.md#maintaining-changelogs) section. +Maintaining dozens of npm packages is difficultβ€”it can be tough to keep track of changes. That's why we use `CHANGELOG.md` files for each package to simplify the release process. As a contributor, you should add an entry to the aforementioned file each time you contribute adding production code as described in [Maintaining Changelogs](https://github.com/WordPress/gutenberg/blob/master/packages/README.md#maintaining-changelogs) section. [lerna]: https://lerna.js.org [npm]: https://www.npmjs.com/ diff --git a/docs/contributors/readme.md b/docs/contributors/readme.md index b04de2a382c606..e51702b7248424 100644 --- a/docs/contributors/readme.md +++ b/docs/contributors/readme.md @@ -14,7 +14,7 @@ Find the section below based on what you are looking to contribute: - **Documentation?** See the [documentation section](/docs/contributors/document.md) -- **Triage Support?** See the [triaging issues section](/docs/contributors/repository-management/#triaging-issues) +- **Triage Support?** See the [triaging issues section](/docs/contributors/triage.md) - **Internationalization?** See the [localizing and translating section](/docs/contributors/localizing.md) diff --git a/docs/contributors/repository-management.md b/docs/contributors/repository-management.md index cf7dbcee1b25eb..e9149f033204bf 100644 --- a/docs/contributors/repository-management.md +++ b/docs/contributors/repository-management.md @@ -23,7 +23,7 @@ Any issues that are irrelevant or not actionable should be closed, because they ### Labels -All issues should have [one or more labels](https://github.com/WordPress/gutenberg/labels). +All issues should have [one or more labels](https://github.com/WordPress/gutenberg/labels). Workflow labels start with β€œNeeds” and may be applied as needed. Ideally, each workflow label will have a group that follows it, such as the Accessibility Team for `Needs Accessibility Feedback`, the Testing Team for `Needs Testing`, etc. @@ -60,32 +60,7 @@ To keep the issue list healthy, it needs to be triaged regularly. *Triage* is th Anyone can help triage, although you’ll need contributor permission on the Gutenberg repository to modify an issue’s labels or edit its title. -To start simply choose from one of these filtered lists of issues: - -- [All Gutenberg issues without an assigned label](https://github.com/wordpress/gutenberg/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-asc+no%3Alabel). Triaging by simply adding labels helps people focused on certain aspects of Gutenberg find relevant issues easier and start working on them. -- [The least recently updated Gutenberg issues](https://github.com/WordPress/gutenberg/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-asc). Triaging issues that are getting old and possibly out of date keeps important work from being overlooked. -- [All Gutenberg issues with no comments](https://github.com/WordPress/gutenberg/issues?q=is%3Aopen+is%3Aissue+sort%3Acomments-asc) Triaging this list helps make sure all issues are acknowledged, and can help identify issues that may need more information or discussion before they are actionable. -- [The least commented on issues](https://github.com/WordPress/gutenberg/issues?q=is%3Aopen+is%3Aissue+sort%3Acomments-asc) Triaging this list helps the community figure out things like traction for certain proposals. - -You can also create your own custom set of filters on GitHub. If you have a filter you think might be useful for the community, feel free to submit a PR to add it to this list. - -When triaging, either one of the lists above or issues in general, here are some steps you can perform: - -- First search for duplicates. If the issue is duplicate, close it by commenting with β€œDuplicate of #” and add any relevant new details to the existing issue. -- If the issue is missing labels, add some to better categorize it (requires proper permissions). -- If the title doesn’t communicate the issue, edit it for clarity (requires proper permissions). -- If it’s a bug report, test to confirm the report or add the `Needs Testing` label. If there is not enough information to confirm the report, add the `[Status] Needs More Info` label and ask for the details needed. -- Remove the `[Status] Needs More Info` if the author of the issue has responded with enough details. -- Close the issue with a note if it has a `[Status] Needs More Info` label but the author didn't respond in 2+ weeks. -- If there was conversation on the issue but no actionable steps identified, follow up with the participants to see what’s actionable. -- If you feel comfortable triaging the issue further, then you can also: - - Check that the bug report is valid by debugging it to see if you can track down the technical specifics. - - Check if the issue is missing some detail and see if you can fill in those details. For instance, if a bug report is missing visual detail, it’s helpful to reproduce the issue locally and upload a screenshot or GIF. - -For triaging there are some labels which are very useful: -- `Needs Technical Feedback` - you can apply them when you see new features or API changes proposed -- `Needs More Info` - when it’s not clear what the issue is or it would help to provide additional details -- `Needs Testing` - it’s useful for old bugs where it seems like they are no longer relevant +See the [Triage Contributors guide](/docs/contributors/triage.md) for details. ## Pull Requests diff --git a/docs/contributors/testing-overview.md b/docs/contributors/testing-overview.md index 5d467ddf2f99a9..390664c8b9da8e 100644 --- a/docs/contributors/testing-overview.md +++ b/docs/contributors/testing-overview.md @@ -344,12 +344,6 @@ test( 'should contain mars if planets is true', () => { It's tempting to snapshot deep renders, but that makes for huge snapshots. Additionally, deep renders no longer test a single component, but an entire tree. With `shallow`, we snapshot just the components that are directly rendered by the component we want to test. -### StoryShots - -> [StoryShots](https://www.npmjs.com/package/@storybook/addon-storyshots) adds automatic Jest Snapshot Testing for [Storybook](https://storybook.js.org/). - -Whenever a new story is added to Storybook, `npm run test-unit` needs to be executed to generate the corresponding snapshots. In the case when the existing story gets updated or removed, please refer to [Working with snapshots](#working-with-snapshots) section. - #### Troubleshooting Sometimes we need to mock refs for some stories which use them. Check the following documents to learn more: @@ -372,7 +366,9 @@ To locally run the tests in debug mode, follow these steps: 5. Click on the "Play" button to resume execution 6. Enjoy debugging the native mobile unit tests! -## End to end Testing +## End-to-end Testing + +End-to-end tests use [Puppeteer](https://github.com/puppeteer/puppeteer) as a headless Chromium driver, and are otherwise still run by a [Jest](https://jestjs.io/) test runner. If you're using the built-in [local environment](/docs/contributors/getting-started.md#local-environment), you can run the e2e tests locally using this command: @@ -419,7 +415,7 @@ Related: https://chromedevtools.github.io/devtools-protocol/tot/Network#method-e ### Core Block Testing -Every core block is required to have at least one set of fixture files for its main save function and one for each deprecation. These fixtures test the parsing and serialization of the block. See [the e2e tests fixtures readme](/packages/e2e-tests/fixtures/blocks/README.md) for more information and instructions. +Every core block is required to have at least one set of fixture files for its main save function and one for each deprecation. These fixtures test the parsing and serialization of the block. See [the e2e tests fixtures readme](https://github.com/wordpress/gutenberg/blob/master/packages/e2e-tests/fixtures/blocks/README.md) for more information and instructions. ## PHP Testing diff --git a/docs/contributors/triage.md b/docs/contributors/triage.md new file mode 100644 index 00000000000000..45e564ebf322d0 --- /dev/null +++ b/docs/contributors/triage.md @@ -0,0 +1,78 @@ +## Get involved in triage +To keep the issue list healthy, it needs to be triaged regularly. Triage is the practice of reviewing existing issues to make sure they’re relevant, actionable, and have all the information they need. +Anyone can help triage, although you’ll need to be a member of the triage team for the Gutenberg repository to modify an issue’s labels or edit its title. + +## Join the triage team +The triage team is an open group of people with a particular role of making sure triage is done consistently across the Gutenberg repo. There are various types of triage which happen: + +* Regular self triage sessions +* Organised triage sessions +* Focusing on a specific board, label or feature to triage + +If you would like to join this team, you can through asking in #core-editor Slack at any time. + +These are the expectations of being a team member: + +* As a member of the triage team, you are expected to at least once a week do some triage even if it is self triage. +* Some people might join this team to focus on a specific label or board, in that case their focus is there. +* Try and join triage sessions. + +## Getting started +To start simply choose from one of these filtered lists of issues: + +* All Gutenberg issues without an assigned label. Triaging by simply adding labels helps people focused on certain aspects of Gutenberg find relevant issues easier and start working on them. +* The least recently updated Gutenberg issues. Triaging issues that are getting old and possibly out of date keeps important work from being overlooked. +* All Gutenberg issues with no comments. Triaging this list helps make sure all issues are acknowledged, and can help identify issues that may need more information or discussion before they are actionable. +* The least commented on issues Triaging this list helps the community figure out things like traction for certain proposals. +* You can also create your own custom set of filters on GitHub. If you have a filter you think might be useful for the community, feel free to submit a PR to add it to this list. + +### Triage itself +When triaging, either one of the lists above or issues in general, work through issues one-by-one. Here are some steps you can perform for each issue: + +* First search for duplicates. If the issue is duplicate, close it by commenting with β€œDuplicate of #” and add any relevant new details to the existing issue. (Don’t forget to search for duplicates among closed issues as well!) +* If the issue is missing labels, add some to better categorize it (requires proper permissions). + ** A good starting place when adding labels is to apply one of the labels prefixed [Type] (e.g. [Type] Enhancement or [Type] Bug) to indicate what kind of issue it is. + ** After that consider adding more descriptive labels. If the issue concerns a particular core block, add one of the labels prefixed [Block]. Or if the issue affects a particular feature there are [Feature] labels. + ** Finally, there are labels that affect particular interest areas, like Accessibility and Internationalization +* Consider adding priority if you can: + ** Priority OMGWTFBBQ: + *** Major issues that are causing failures and are reported frequently. + *** Typically, these are issues that are critical because they break important behaviour or functionality. + *** An example might be, β€œUnable to remove a block after it is added to the editor”. . + ** Priority: High: + *** Fits one of the current focuses: usually placing in that project board. + *** Major broken experience (including flow, visual bugs and blocks). + ** Priority: Low: + *** Enhancements that aren’t part of focuses. + *** Niche bugs. + *** Old browsers + ** Note that no priority label infers normal. +* If the title doesn’t communicate the issue, edit it for clarity (requires proper permissions). +* If it’s a bug report, test to confirm the report or add the Needs Testing label. If there is not enough information to confirm the report, add the [Status] Needs More Info label and ask for the details needed. It’s particularly beneficial when a bug report has steps for reproduction, ask the reporter to add those if they’re missing. +* Remove the [Status] Needs More Info if the author of the issue has responded with enough details. +* Close the issue with a note if it has a [Status] Needs More Info label but the author didn't respond in 2+ weeks. +* If there was a conversation on the issue but no actionable steps identified, follow up with the participants to see what’s actionable. +* If you feel comfortable triaging the issue further, then you can also: + ** Check that the bug report is valid by debugging it to see if you can track down the technical specifics. + ** Check if the issue is missing some detail and see if you can fill in those details. For instance, if a bug report is missing visual detail, it’s helpful to reproduce the issue locally and upload a screenshot or GIF. + ** Consider adding the Good First Issue label if you believe this is a relatively easy issue for a first-time contributor to try to solve. + +For triaging there are some labels which are very useful: +* Needs Technical Feedback - you can apply them when you see new features or API changes proposed +* Needs More Info - when it’s not clear what the issue is or it would help to provide additional details +* Needs Testing - it’s useful for old bugs where it seems like they are no longer relevant + +## Design specific triage +Along with the general triage flows listed previously, there are some specific additions to the flows for more design-centric triage: + +* PR testing and reviews: ideally this is your first stop, particularly in daily self triage. +* Needs design feedback: check this does need design feedback and if possible give it. You can organise this by priority, project boards or by least commented. + ** Ask for screenshots to see if unable to. + ** Ask for iterations and note need to change before merging. + ** Once enough opinions remove the label and either go to needs design. + ** If this isn’t in a board, check it doesn’t fit in a specific focus. + ** If the issue/pull has not been prioritized yet, consider adding a priority. +* Needs design: + ** Does it really need a design? + ** Does this fit a focus? + ** If it has a design mark as β€˜needs design feedback’. diff --git a/docs/designers-developers/designers/block-design.md b/docs/designers-developers/designers/block-design.md index 93660a307eb9fe..b1f73d30c959d1 100644 --- a/docs/designers-developers/designers/block-design.md +++ b/docs/designers-developers/designers/block-design.md @@ -76,7 +76,7 @@ Avoid long, multi-line block names. Every block should include a description that clearly explains the block's function. The description will display in the Settings Sidebar. -You can add a description by using the description attribute in the [registerBlockType function](/docs/designers-developers/developers/block-api/block-registration/). +You can add a description by using the description attribute in the [registerBlockType function](/docs/designers-developers/developers/block-api/block-registration.md). Stick to a single imperative sentence with an action + subject format. Examples: diff --git a/docs/designers-developers/designers/design-patterns.md b/docs/designers-developers/designers/user-interface.md similarity index 72% rename from docs/designers-developers/designers/design-patterns.md rename to docs/designers-developers/designers/user-interface.md index bf06df6da5e9df..1d688e27838d64 100644 --- a/docs/designers-developers/designers/design-patterns.md +++ b/docs/designers-developers/designers/user-interface.md @@ -1,18 +1,18 @@ -# Patterns +# User Interface -## Basic Editor Interface +## The Block Editor -The block editor’s general layout uses on a bar at the top, with content below. +The block editor’s general layout uses a bar at the top, with content below. ![Editor Interface](https://cldup.com/VWA_jMcIRw-3000x3000.png) -The **Toolbar** contains document-level actions: Editor mode, save status, global actions for undo/redo/insert, the settings toggle, and publish options. +The **Toolbar** contains document-level actions: Editor/Select modes, save status, global actions for undo/redo/insert, the settings toggle, and publish options. The **Content Area** contains the document itself. The **Settings Sidebar** contains additional settings for the document (tags, categories, schedule etc.) and for blocks in the β€œBlock” tab. A cog button in the toolbar hides the Settings Sidebar, allowing the user to enjoy a more immersive writing experience. On small screens, the sidebar is hidden by default. -## The Block Interface +## The Block The block itself is the most basic unit of the editor. Generally speaking, everything is a block. Users build posts and pages using blocks, mimicking the vertical flow of the underlying HTML markup. @@ -24,11 +24,11 @@ A selected block shows a number of contextual actions: The block interface has basic actions. The block editor aims for good, common defaults, so users should be able to create a complete document without actually needing the advanced actions in the Settings Sidebar. -**The Block Toolbar** highlights commonly-used actions. The **Block Chip** lives in the block toolbar, and contains high-level controls for the selected block. It primarily allows users to transform a block into another type of compatible block. Some blocks also use the block chip to users to choose from a set of alternate block styles. +**The Block Toolbar** highlights commonly-used actions. The **Block Icon** lives in the block toolbar, and contains high-level controls for the selected block. It primarily allows users to transform a block into another type of compatible block. Some blocks also use the block icon for users to choose from a set of alternate block styles. The **Block Formatting** options let users adjust block-level settings, and the **Inline Formatting** options allow adjustments to elements inside the block. When a block is long, the block toolbar pins itself to the top of the screen as the user scrolls down the page. -Blocks can be moved up and down via the **Block Mover** icons on the left. Additional block actions are available on the right via an ellipsis menu: deleting and duplicating blocks, as well as **advanced actions** like β€œEdit as HTML” and β€œConvert to Reusable Block.” +Blocks can be moved up and down via the **Block Mover** icons. Additional block actions are available via an ellipsis menu: deleting and duplicating blocks, as well as **advanced actions** like β€œEdit as HTML” and β€œConvert to Reusable Block.” An unselected block does not show the block toolbar or any other contextual controls. In effect, an unselected block is a preview of the content itself: @@ -47,7 +47,7 @@ The sidebar has two tabs, Document and Block: Each tab has sets of editable fields (**Sidebar Sections**) that users can toggle open or closed. -If a block requires advanced configuration, those settings should live in the Settings sidebar (Editor block settings can also be reached directly by clicking the cog icon next to a block). Don’t put anything in the sidebar block tab that is necessary for the basic operation of your block; your user might dismiss the sidebar for an immersive writing experience. Pick good defaults, and make important actions available in the block toolbar. +If a block requires advanced configuration, those settings should live in the Settings Sidebar. Don’t put anything in the sidebar block tab that is necessary for the basic operation of your block; your user might dismiss the sidebar for an immersive writing experience. Pick good defaults, and make important actions available in the block toolbar. Actions that could go in the block tab of the sidebar could be: @@ -60,6 +60,4 @@ Actions that could go in the block tab of the sidebar could be: ![Block Library](https://cldup.com/7QoQIoLk-A-3000x3000.png) -The **Block Library** appears when someone inserts a block, whether via the toolbar, or contextually within the content area. Inside, blocks are organized into expandable sections. The block library’s search bar auto-filters the list of blocks as the user types. Users can choose a block by selecting the **Block Button** or the **Block Name**. - -**Parent Blocks** (Blocks that contain children blocks) are represented by a layered block button. +The **Block Library** appears when someone inserts a block, whether via the toolbar, or contextually within the content area. Inside, blocks are organized into expandable sections. The block library’s search bar auto-filters the list of blocks as the user types. Users can choose a block by selecting the **Block Button** or the **Block Name**. diff --git a/docs/designers-developers/developers/backward-compatibility/deprecations.md b/docs/designers-developers/developers/backward-compatibility/deprecations.md index cf721c44875c6c..9947d262b243cb 100644 --- a/docs/designers-developers/developers/backward-compatibility/deprecations.md +++ b/docs/designers-developers/developers/backward-compatibility/deprecations.md @@ -241,11 +241,11 @@ For features included in the Gutenberg plugin, the deprecation policy is intende ## 3.0.0 - `wp.blocks.registerCoreBlocks` function removed. Please use `wp.coreBlocks.registerCoreBlocks` instead. - - Raw TinyMCE event handlers for `RichText` have been deprecated. Please use [documented props](/packages/editor/src/components/rich-text/README.md), ancestor event handler, or onSetup access to the internal editor instance event hub instead. + - Raw TinyMCE event handlers for `RichText` have been deprecated. Please use [documented props](https://github.com/WordPress/gutenberg/blob/v3.0.0/editor/components/rich-text/README.md), ancestor event handler, or onSetup access to the internal editor instance event hub instead. ## 2.8.0 - - `Original autocompleter interface in wp.components.Autocomplete` updated. Please use `latest autocompleter interface` instead. See [autocomplete](/packages/components/src/autocomplete/README.md) for more info. + - `Original autocompleter interface in wp.components.Autocomplete` updated. Please use `latest autocompleter interface` instead. See [autocomplete](https://github.com/WordPress/gutenberg/blob/v2.8.0/components/autocomplete/README.md) for more info. - `getInserterItems`: the `allowedBlockTypes` argument is now mandatory. - `getFrecentInserterItems`: the `allowedBlockTypes` argument is now mandatory. diff --git a/docs/designers-developers/developers/block-api/README.md b/docs/designers-developers/developers/block-api/README.md index 52ed3a17a4493b..284b0db24df488 100644 --- a/docs/designers-developers/developers/block-api/README.md +++ b/docs/designers-developers/developers/block-api/README.md @@ -2,10 +2,12 @@ Blocks are the fundamental element of the editor. They are the primary way in which plugins and themes can register their own functionality and extend the capabilities of the editor. -## Registering a block - -All blocks must be registered before they can be used in the editor. You can learn about block registration, and the available options, in the [block registration](/docs/designers-developers/developers/block-api/block-registration.md) documentation. - -## Block `edit` and `save` - -The `edit` function defines the components for the block in the editor interface the user interacts with. The `save` function defines the markup to be serialized back when a post is saved. They are the heart of how a block operates, so they are [covered separately](/docs/designers-developers/developers/block-api/block-edit-save.md). +The following sections will walk you through the existing block APIs: + +- [Block registration](/docs/designers-developers/developers/block-api/block-registration.md). +- [Edit and Save](/docs/designers-developers/developers/block-api/block-edit-save.md) +- [Attributes](/docs/designers-developers/developers/block-api/block-attributes.md) +- [Deprecated blocks](/docs/designers-developers/developers/block-api/block-deprecation.md) +- [Templates](/docs/designers-developers/developers/block-api/block-templates.md) +- [Annotations](/docs/designers-developers/developers/block-api/block-annotations.md) +- [Patterns (experimental)](/docs/designers-developers/developers/block-api/block-patterns.md) diff --git a/docs/designers-developers/developers/block-api/block-attributes.md b/docs/designers-developers/developers/block-api/block-attributes.md index 386210c6e998ac..5d60dbc9306b7b 100644 --- a/docs/designers-developers/developers/block-api/block-attributes.md +++ b/docs/designers-developers/developers/block-api/block-attributes.md @@ -1,5 +1,21 @@ # Attributes +## Type Validation + +The only required field for an attribute is the `type` field. It indicates the type of data that is stored within the attribute. + +Accepted values in the `type` field MUST be one of the following: + +* null +* boolean +* object +* array +* number +* string +* integer + +See [WordPress's REST API documentation](https://developer.wordpress.org/rest-api/extending-the-rest-api/schema/) for additional details. + ## Common Sources Attribute sources are used to define how the block attribute values are extracted from saved post content. They provide a mechanism to map from the saved markup to a JavaScript representation of a block. @@ -33,19 +49,33 @@ _Example_: Extract the `src` attribute from an image found in the block's markup // { "url": "https://lorempixel.com/1200/800/" } ``` -#### `attribute` Type Validation +Most attributes from markup will be of type `string`. Numeric attributes in HTML are still stored as strings, and are not converted automatically. -Accepted values in the `type` field of an `attribute` MUST be one of the following: +```js +{ + width: { + type: 'string', + source: 'attribute', + selector: 'img', + attribute: 'width', + } +} +// { "width": "50" } +``` -* null -* boolean -* object -* array -* number -* string -* integer +The only exception is when checking for the existence of an attribute (for example, the `disabled` attribute on a `button`). In that case type `boolean` can be used and the stored value will be a boolean. -See [WordPress's REST API documentation](https://developer.wordpress.org/rest-api/extending-the-rest-api/schema/) for additional details. +```js +{ + disabled: { + type: 'boolean', + source: 'attribute', + selector: 'button', + attribute: 'disabled', + } +} +// { "disabled": true } +``` ### `text` diff --git a/docs/designers-developers/developers/block-api/block-context.md b/docs/designers-developers/developers/block-api/block-context.md new file mode 100644 index 00000000000000..56289ef088c3e2 --- /dev/null +++ b/docs/designers-developers/developers/block-api/block-context.md @@ -0,0 +1,76 @@ +# Block Context + +Block context is a feature which enables ancestor blocks to provide values which can be consumed by descendent blocks within its own hierarchy. Those descendent blocks can inherit these values without resorting to hard-coded values and without an explicit awareness of the block which provides those values. + +This is especially useful in full-site editing where, for example, the contents of a block may depend on the context of the post in which it is displayed. A blogroll template may show excerpts of many different posts. Using block context, there can still be one single "Post Excerpt" block which displays the contents of the post based on an inherited post ID. + +If you are familiar with [React Context](https://reactjs.org/docs/context.html), block context adopts many of the same ideas. In fact, the client-side block editor implementation of block context is a very simple application of React Context. Block context is also supported in server-side `render_callback` implementations, demonstrated in the examples below. + +## Defining Block Context + +Block context is defined in the registered settings of a block. A block can provide a context value, or consume a value it seeks to inherit. + +### Providing Block Context + +A block can provide a context value by assigning a `providesContext` property in its registered settings. This is an object which maps a context name to one of the block's own attribute. The value corresponding to that attribute value is made available to descendent blocks and can be referenced by the same context name. Currently, block context only supports values derived from the block's own attributes. This could be enhanced in the future to support additional sources of context values. + +`record/block.json` + +```json +{ + "name": "my-plugin/record", + "attributes": { + "recordId": { + "type": "number" + } + }, + "providesContext": { + "my-plugin/recordId": "recordId" + } +} +``` + +As seen in the above example, it is recommended that you include a namespace as part of the name of the context key so as to avoid potential conflicts with other plugins or default context values provided by WordPress. The context namespace should be specific to your plugin, and in most cases can be the same as used in the name of the block itself. + +### Consuming Block Context + +A block can inherit a context value from an ancestor provider by assigning a `context` property in its registered settings. This should be assigned as an array of the context names the block seeks to inherit. + +`record-title/block.json` + +```json +{ + "name": "my-plugin/record-title", + "context": [ "my-plugin/recordId" ] +} +``` + +## Using Block Context + +Once a block has defined the context it seeks to inherit, this can be accessed in the implementation of `edit` (JavaScript) and `render_callback` (PHP). It is provided as an object (JavaScript) or associative array (PHP) of the context values which have been defined for the block. Note that a context value will only be made available if the block explicitly defines a desire to inherit that value. + +### JavaScript + +`record-title/index.js` + +```js +registerBlockType( 'my-plugin/record-title', { + edit( { context } ) { + return 'The current record ID is: ' + context[ 'my-plugin/recordId' ]; + }, +} ); +``` + +### PHP + +A block's context values are available from the `context` property of the `$block` argument passed to the `render_callback` function. + +`record-title/index.php` + +```php +register_block_type( 'my-plugin/record-title', [ + 'render_callback' => function( $block ) { + return 'The current record ID is: ' . $block->context['my-plugin/recordId']; + }, +] ); +``` diff --git a/docs/designers-developers/developers/block-api/block-deprecation.md b/docs/designers-developers/developers/block-api/block-deprecation.md index b07ae89e1a0a7c..067885f0708efd 100644 --- a/docs/designers-developers/developers/block-api/block-deprecation.md +++ b/docs/designers-developers/developers/block-api/block-deprecation.md @@ -277,4 +277,4 @@ registerBlockType( 'gutenberg/block-with-deprecated-version', { In the example above we updated the block to use an inner Paragraph block with a title instead of a title attribute. -*Above are example cases of block deprecation. For more, real-world examples, check for deprecations in the [core block library](/packages/block-library/src/README.md). Core blocks have been updated across releases and contain simple and complex deprecations.* +*Above are example cases of block deprecation. For more, real-world examples, check for deprecations in the [core block library](https://github.com/WordPress/gutenberg/tree/master/packages/block-library/src). Core blocks have been updated across releases and contain simple and complex deprecations.* diff --git a/docs/designers-developers/developers/block-api/block-patterns.md b/docs/designers-developers/developers/block-api/block-patterns.md new file mode 100644 index 00000000000000..951818af01ebcb --- /dev/null +++ b/docs/designers-developers/developers/block-api/block-patterns.md @@ -0,0 +1,37 @@ +# Patterns (Experimental) + +Patterns are predefined block layouts, ready to insert and tweak. + +**Note** Patterns are still under heavy development and the APIs are subject to change. + +#### register_pattern + +The editor comes with a list of built-in patterns. Theme and plugin authors can register addition custom patterns using the `register_pattern` function. + +The `register_pattern` function receives the name of the pattern as the first argument and an array describing properties of the pattern as the second argument. + +The properties of the style array must include `name` and `label`: + - `title`: A human-readable title for the pattern. + - `content`: Raw HTML content for the pattern. + +```php +register_pattern( + 'my-plugin/my-awesome-pattern', + array( + 'title' => __( 'Two buttons', 'my-plugin' ), + 'content' => "\n\n", + ) +); +``` + +#### unregister_pattern + +`unregister_pattern` allows unregistering a pattern previously registered on the server using `register_pattern`. + +The function's argument is the registered name of the pattern. + +The following code sample unregisters the style named 'my-plugin/my-awesome-pattern': + +```php +unregister_pattern( 'my-plugin/my-awesome-pattern' ); +``` diff --git a/docs/designers-developers/developers/block-api/block-templates.md b/docs/designers-developers/developers/block-api/block-templates.md index 49279a86595ed1..ad961e8f8066d1 100644 --- a/docs/designers-developers/developers/block-api/block-templates.md +++ b/docs/designers-developers/developers/block-api/block-templates.md @@ -32,7 +32,7 @@ function myplugin_register_template() { add_action( 'init', 'myplugin_register_template' ); ``` -The following example in JavaScript creates a new block using [InnerBlocks](/packages/block-editor/src/components/inner-blocks/README.md) and templates, when inserted creates a set of blocks based off the template. +The following example in JavaScript creates a new block using [InnerBlocks](https://github.com/WordPress/gutenberg/blob/master/packages/block-editor/src/components/inner-blocks/README.md) and templates, when inserted creates a set of blocks based off the template. ```js const el = wp.element.createElement; diff --git a/docs/designers-developers/developers/data/data-core-annotations.md b/docs/designers-developers/developers/data/data-core-annotations.md index e71aefd27d2129..0b5840c617d1e4 100644 --- a/docs/designers-developers/developers/data/data-core-annotations.md +++ b/docs/designers-developers/developers/data/data-core-annotations.md @@ -4,17 +4,17 @@ Namespace: `core/annotations`. ## Selectors - + Nothing to document. - - + ## Actions - + Nothing to document. - + + diff --git a/docs/designers-developers/developers/data/data-core-block-editor.md b/docs/designers-developers/developers/data/data-core-block-editor.md index 588b1f27e32499..e19a7cb52c12b1 100644 --- a/docs/designers-developers/developers/data/data-core-block-editor.md +++ b/docs/designers-developers/developers/data/data-core-block-editor.md @@ -4,7 +4,7 @@ Namespace: `core/block-editor`. ## Selectors - + # **canInsertBlockType** @@ -706,6 +706,19 @@ _Returns_ - `boolean`: Whether an ancestor of the block is in multi-selection set. +# **isBlockHighlighted** + +Returns true if the current highlighted block matches the block clientId. + +_Parameters_ + +- _state_ `Object`: Global application state. +- _clientId_ `string`: The block to check. + +_Returns_ + +- `boolean`: Whether the block is currently highlighted. + # **isBlockInsertionPointVisible** Returns true if we should show the block insertion point. @@ -894,12 +907,11 @@ _Returns_ - `?boolean`: Whether the template is valid or not. - - + ## Actions - + # **clearSelectedBlock** @@ -1296,6 +1308,15 @@ _Returns_ - `Object`: Action object. +# **toggleBlockHighlight** + +Returns an action object that toggles the highlighted block state. + +_Parameters_ + +- _clientId_ `string`: The block's clientId. +- _isHighlighted_ `boolean`: The highlight state. + # **toggleBlockMode** Returns an action object used to toggle the block editing mode between @@ -1364,6 +1385,15 @@ _Returns_ # **updateSettings** -Undocumented declaration. +Returns an action object used in signalling that the block editor settings have been updated. + +_Parameters_ + +- _settings_ `Object`: Updated settings + +_Returns_ + +- `Object`: Action object + - + diff --git a/docs/designers-developers/developers/data/data-core-blocks.md b/docs/designers-developers/developers/data/data-core-blocks.md index 933c432cd93260..8d577f4fca040c 100644 --- a/docs/designers-developers/developers/data/data-core-blocks.md +++ b/docs/designers-developers/developers/data/data-core-blocks.md @@ -4,7 +4,7 @@ Namespace: `core/blocks`. ## Selectors - + # **getBlockStyles** @@ -231,12 +231,11 @@ _Returns_ - `Array`: Whether block type matches search term. - - + ## Actions - + # **addBlockCollection** @@ -417,4 +416,5 @@ _Returns_ - `Object`: Action object. - + + diff --git a/docs/designers-developers/developers/data/data-core-edit-post.md b/docs/designers-developers/developers/data/data-core-edit-post.md index 49801a69817be8..05714b83bcda7b 100644 --- a/docs/designers-developers/developers/data/data-core-edit-post.md +++ b/docs/designers-developers/developers/data/data-core-edit-post.md @@ -4,7 +4,7 @@ Namespace: `core/edit-post`. ## Selectors - + # **getActiveGeneralSidebarName** @@ -267,21 +267,16 @@ _Returns_ - `boolean`: Whether the metaboxes are being saved. - - + ## Actions - + # **closeGeneralSidebar** Returns an action object signalling that the user closed the sidebar. -_Returns_ - -- `Object`: Action object. - # **closeModal** Returns an action object signalling that the user closed a modal. @@ -326,11 +321,7 @@ Returns an action object used in signalling that the user opened an editor sideb _Parameters_ -- _name_ `string`: Sidebar name to be opened. - -_Returns_ - -- `Object`: Action object. +- _name_ `?string`: Sidebar name to be opened. # **openModal** @@ -472,4 +463,5 @@ _Returns_ - `Object`: Action object. - + + diff --git a/docs/designers-developers/developers/data/data-core-editor.md b/docs/designers-developers/developers/data/data-core-editor.md index ef0243465e9f3c..ffba8e67b9aa30 100644 --- a/docs/designers-developers/developers/data/data-core-editor.md +++ b/docs/designers-developers/developers/data/data-core-editor.md @@ -4,7 +4,7 @@ Namespace: `core/editor`. ## Selectors - + # **canInsertBlockType** @@ -1060,12 +1060,11 @@ _Related_ - isValidTemplate in core/block-editor store. - - + ## Actions - + # **autosave** @@ -1511,4 +1510,5 @@ _Returns_ - `Object`: Action object. - + + diff --git a/docs/designers-developers/developers/data/data-core-keyboard-shortcuts.md b/docs/designers-developers/developers/data/data-core-keyboard-shortcuts.md index 9db8ab7ce2d362..fefa8e189e2150 100644 --- a/docs/designers-developers/developers/data/data-core-keyboard-shortcuts.md +++ b/docs/designers-developers/developers/data/data-core-keyboard-shortcuts.md @@ -4,7 +4,7 @@ Namespace: `core/keyboard-shortcuts`. ## Selectors - + # **getAllShortcutRawKeyCombinations** @@ -85,12 +85,11 @@ _Returns_ - `?string`: Shortcut representation. - - + ## Actions - + # **registerShortcut** @@ -116,4 +115,5 @@ _Returns_ - `Object`: action. - + + diff --git a/docs/designers-developers/developers/data/data-core-notices.md b/docs/designers-developers/developers/data/data-core-notices.md index 876977576f69bd..54dfbdd8d84ed8 100644 --- a/docs/designers-developers/developers/data/data-core-notices.md +++ b/docs/designers-developers/developers/data/data-core-notices.md @@ -4,7 +4,7 @@ Namespace: `core/notices`. ## Selectors - + # **getNotices** @@ -20,12 +20,11 @@ _Returns_ - `Array`: Array of notices. - - + ## Actions - + # **createErrorNotice** @@ -132,4 +131,5 @@ _Returns_ - `Object`: Action object. - + + diff --git a/docs/designers-developers/developers/data/data-core-nux.md b/docs/designers-developers/developers/data/data-core-nux.md index 92dcf6be1d0ac2..ad0a93e2bde235 100644 --- a/docs/designers-developers/developers/data/data-core-nux.md +++ b/docs/designers-developers/developers/data/data-core-nux.md @@ -4,7 +4,7 @@ Namespace: `core/nux`. ## Selectors - + # **areTipsEnabled** @@ -47,12 +47,11 @@ _Returns_ - `boolean`: Whether or not the given tip is showing. - - + ## Actions - + # **disableTips** @@ -97,4 +96,5 @@ _Returns_ - `Object`: Action object. - + + diff --git a/docs/designers-developers/developers/data/data-core-viewport.md b/docs/designers-developers/developers/data/data-core-viewport.md index b8f133834ec594..4f776c53efbca7 100644 --- a/docs/designers-developers/developers/data/data-core-viewport.md +++ b/docs/designers-developers/developers/data/data-core-viewport.md @@ -4,7 +4,7 @@ Namespace: `core/viewport`. ## Selectors - + # **isViewportMatch** @@ -26,12 +26,11 @@ _Returns_ - `boolean`: Whether viewport matches query. - - + ## Actions - + # **setIsMatching** @@ -47,4 +46,5 @@ _Returns_ - `Object`: Action object. - + + diff --git a/docs/designers-developers/developers/data/data-core.md b/docs/designers-developers/developers/data/data-core.md index 79f3f41991c08f..142538c6354687 100644 --- a/docs/designers-developers/developers/data/data-core.md +++ b/docs/designers-developers/developers/data/data-core.md @@ -4,7 +4,7 @@ Namespace: `core`. ## Selectors - + # **canUser** @@ -71,6 +71,18 @@ _Returns_ - `?Array`: An array of autosaves for the post, or undefined if there is none. +# **getCurrentTheme** + +Return the current theme. + +_Parameters_ + +- _state_ `Object`: Data state. + +_Returns_ + +- `Object`: The current theme. + # **getCurrentUser** Returns the current user. @@ -200,7 +212,7 @@ _Parameters_ _Returns_ -- `Array`: Records. +- `?Array`: Records. # **getLastEntitySaveError** @@ -441,12 +453,11 @@ _Returns_ - `boolean`: Whether the entity record is saving or not. - - + ## Actions - + # **addEntities** @@ -492,6 +503,18 @@ _Returns_ - `Object`: Action object. +# **receiveCurrentTheme** + +Returns an action object used in signalling that the current theme has been received. + +_Parameters_ + +- _currentTheme_ `Object`: The current theme. + +_Returns_ + +- `Object`: Action object. + # **receiveCurrentUser** Returns an action used in signalling that the current user has been received. @@ -617,4 +640,5 @@ _Parameters_ Action triggered to undo the last edit to an entity record, if any. - + + diff --git a/docs/designers-developers/developers/platform/README.md b/docs/designers-developers/developers/platform/README.md index dae0944cb1ef0d..5bd14bbb2bd18c 100644 --- a/docs/designers-developers/developers/platform/README.md +++ b/docs/designers-developers/developers/platform/README.md @@ -5,7 +5,7 @@ The Gutenberg Project is not only building a better editor for WordPress, but al ## UI Components -The [WordPress Components package](/docs/components/) contains a set of UI components you can use in your project. See the [WordPress Storybook site](https://wordpress.github.io/gutenberg/) for an interactive guide to the available components and settings. +The [WordPress Components package](/packages/components/README.md) contains a set of UI components you can use in your project. See the [WordPress Storybook site](https://wordpress.github.io/gutenberg/) for an interactive guide to the available components and settings. Here is a quick example, how to use components in your project. @@ -27,6 +27,8 @@ function MyApp() { } ``` +Many components include CSS to add style, you will need to include for the components to appear correctly. The component stylesheet can be found in `node_modules/@wordpress/components/build-style/style.css`, you can link directly or copy and include it in your project. + ## Development Scripts The [wp-scripts package](https://developer.wordpress.org/block-editor/packages/packages-scripts/) is a collection of reusable scripts for JavaScript development β€” includes scripts for building, linting, and testing β€” all with no additional configuration files. diff --git a/docs/designers-developers/developers/tutorials/block-tutorial/creating-dynamic-blocks.md b/docs/designers-developers/developers/tutorials/block-tutorial/creating-dynamic-blocks.md index d481c5e3f0d627..84a6fc4f1489f5 100644 --- a/docs/designers-developers/developers/tutorials/block-tutorial/creating-dynamic-blocks.md +++ b/docs/designers-developers/developers/tutorials/block-tutorial/creating-dynamic-blocks.md @@ -99,7 +99,7 @@ Because it is a dynamic block it doesn't need to override the default `save` imp * Plugin Name: Gutenberg examples dynamic */ -function gutenberg_examples_dynamic_render_callback( $attributes, $content ) { +function gutenberg_examples_dynamic_render_callback( $block, $content ) { $recent_posts = wp_get_recent_posts( array( 'numberposts' => 1, 'post_status' => 'publish', @@ -141,11 +141,19 @@ There are a few things to notice: * The `edit` function still shows a representation of the block in the editor's context (this could be very different from the rendered version, it's up to the block's author) * The built-in `save` function just returns `null` because the rendering is performed server-side. -* The server-side rendering is a function taking the block attributes and the block inner content as arguments, and returning the markup (quite similar to shortcodes) +* The server-side rendering is a function taking the block and the block inner content as arguments, and returning the markup (quite similar to shortcodes) + +Note that for convenience and for backward-compatibility, the first argument of a `render_callback` function can also be referenced as an associative array of the block's attributes: + +```php +function gutenberg_examples_dynamic_render_callback( $block_attributes ) { + return 'The record ID is: ' . esc_html( $block_attributes['recordId'] ); +} +``` ## Live rendering in the block editor -Gutenberg 2.8 added the [``](/packages/components/src/server-side-render) block which enables rendering to take place on the server using PHP rather than in JavaScript. +Gutenberg 2.8 added the [``](/packages/server-side-render/README.md) block which enables rendering to take place on the server using PHP rather than in JavaScript. *Server-side render is meant as a fallback; client-side rendering in JavaScript is always preferred (client rendering is faster and allows better editor manipulation).* diff --git a/docs/designers-developers/developers/tutorials/block-tutorial/nested-blocks-inner-blocks.md b/docs/designers-developers/developers/tutorials/block-tutorial/nested-blocks-inner-blocks.md index 8807f02596e242..41748c56995bfe 100644 --- a/docs/designers-developers/developers/tutorials/block-tutorial/nested-blocks-inner-blocks.md +++ b/docs/designers-developers/developers/tutorials/block-tutorial/nested-blocks-inner-blocks.md @@ -1,6 +1,6 @@ # Nested Blocks: Using InnerBlocks -You can create a single block that nests other blocks using the [InnerBlocks](/packages/block-editor/src/components/inner-blocks) component. This is used in the Columns block, Social Links block, or any block you want to contain other blocks. +You can create a single block that nests other blocks using the [InnerBlocks](https://github.com/WordPress/gutenberg/tree/master/packages/block-editor/src/components/inner-blocks/README.md) component. This is used in the Columns block, Social Links block, or any block you want to contain other blocks. Note: A single block can only contain one `InnerBlock` component. @@ -125,7 +125,7 @@ const MY_TEMPLATE = [ ``` {% end %} -Use the `templateLock` property to lock down the template. Using `all` locks the template complete, no changes can be made. Using `insert` prevents additional blocks to be inserted, but existing blocks can be reorderd. See [templateLock documentation](/packages/block-editor/src/components/inner-blocks#templatelock) for additional information. +Use the `templateLock` property to lock down the template. Using `all` locks the template complete, no changes can be made. Using `insert` prevents additional blocks to be inserted, but existing blocks can be reorderd. See [templateLock documentation](https://github.com/WordPress/gutenberg/tree/master/packages/block-editor/src/components/inner-blocks/README.md#templatelock) for additional information. ### Post Template diff --git a/docs/designers-developers/developers/tutorials/format-api/2-toolbar-button.md b/docs/designers-developers/developers/tutorials/format-api/2-toolbar-button.md index a3ded1c493bfea..88840f1059020a 100644 --- a/docs/designers-developers/developers/tutorials/format-api/2-toolbar-button.md +++ b/docs/designers-developers/developers/tutorials/format-api/2-toolbar-button.md @@ -1,6 +1,6 @@ # Add a Button to the Toolbar -Now that the format is available, the next step is to surface it to the UI. You can make use of the [`RichTextToolbarButton`](/packages/editor/src/components/rich-text/README.md#RichTextToolbarButton) component to extend the format toolbar. +Now that the format is available, the next step is to surface it to the UI. You can make use of the [`RichTextToolbarButton`](https://github.com/WordPress/gutenberg/tree/master/packages/block-editor/src/components/rich-text#richtexttoolbarbutton) component to extend the format toolbar. Paste this code in `my-custom-format.js`: diff --git a/docs/designers-developers/developers/tutorials/metabox/meta-block-3-add.md b/docs/designers-developers/developers/tutorials/metabox/meta-block-3-add.md index 4bf4c70ae646d5..9d5eaf2e403e5c 100644 --- a/docs/designers-developers/developers/tutorials/metabox/meta-block-3-add.md +++ b/docs/designers-developers/developers/tutorials/metabox/meta-block-3-add.md @@ -2,11 +2,9 @@ With the meta field registered in the previous step, next you will create a new block used to display the field value to the user. See the [Block Tutorial](/docs/designers-developers/developers/tutorials/block-tutorial/readme.md) for a deeper understanding of creating custom blocks. -For this block, you will use the TextControl component, which is similar to an HTML input text field. For additional components, check out the [components](/packages/components/src) and [editor](/packages/editor/src/components) packages repositories. +For this block, you will use the TextControl component, which is similar to an HTML input text field. For additional components, check out the [Component Reference](/packages/components/README.md). -Attributes are the information displayed in blocks. As shown in the block tutorial, the source of attributes come from the text or HTML a user writes in the editor. For your meta block, the attribute will come from the post meta field. - -By specifying the source of the attributes as `meta`, the block editor automatically handles the loading and storing of the data; no REST API or data functions are needed. +The hook `useEntityProp` can be used by the blocks to get or change meta values. Add this code to your JavaScript file (this tutorial will call the file `myguten.js`): @@ -17,26 +15,42 @@ Add this code to your JavaScript file (this tutorial will call the file `myguten var el = wp.element.createElement; var registerBlockType = wp.blocks.registerBlockType; var TextControl = wp.components.TextControl; + var useSelect = wp.data.useSelect; + var useEntityProp = wp.coreData.useEntityProp; registerBlockType( 'myguten/meta-block', { title: 'Meta Block', icon: 'smiley', category: 'common', - attributes: { - blockValue: { - type: 'string', - source: 'meta', - meta: 'myguten_meta_block_field', - }, - }, - edit: function( props ) { var className = props.className; - var setAttributes = props.setAttributes; - function updateBlockValue( blockValue ) { - setAttributes( { blockValue } ); + var postType = useSelect( + function( select ) { + return select( 'core/editor' ).getCurrentPostType(); + }, + [] + ); + var entityProp = useEntityProp( + 'postType', + postType, + 'meta' + ); + var meta = entityProp[ 0 ]; + var setMeta = entityProp[ 1 ]; + + var metaFieldValue = meta['myguten_meta_block_field']; + function updateMetaValue( newValue ) { + setMeta( + Object.assign( + {}, + meta, + { + 'myguten_meta_block_field': newValue, + } + ) + ); } return el( @@ -44,8 +58,8 @@ Add this code to your JavaScript file (this tutorial will call the file `myguten { className: className }, el( TextControl, { label: 'Meta Block Field', - value: props.attributes.blockValue, - onChange: updateBlockValue, + value: metaFieldValue, + onChange: updateMetaValue, } ) ); }, @@ -62,38 +76,42 @@ Add this code to your JavaScript file (this tutorial will call the file `myguten ```js import { registerBlockType } from '@wordpress/blocks'; import { TextControl } from '@wordpress/components'; +import { useSelect } from '@wordpress/data'; +import { useEntityProp } from '@wordpress/core-data'; registerBlockType( 'myguten/meta-block', { title: 'Meta Block', icon: 'smiley', category: 'common', - attributes: { - blockValue: { - type: 'string', - source: 'meta', - meta: 'myguten_meta_block_field', - }, - }, - edit( { className, setAttributes, attributes } ) { - function updateBlockValue( blockValue ) { - setAttributes( { blockValue } ); + const postType = useSelect( + ( select ) => select( 'core/editor' ).getCurrentPostType(), + [] + ); + const [ meta, setMeta ] = useEntityProp( + 'postType', + postType, + 'meta' + ); + const metaFieldValue = meta['myguten_meta_block_field']; + function updateMetaValue( newValue ) { + setMeta( { ...meta, 'myguten_meta_block_field': newValue } ); } return (
); }, // No information saved to the block - // Data is saved to post meta via attributes + // Data is saved to post meta via the hook save() { return null; }, @@ -101,14 +119,14 @@ registerBlockType( 'myguten/meta-block', { ``` {% end %} -**Important:** Before you test, you need to enqueue your JavaScript file and its dependencies. Note the WordPress packages used above are `wp.element`, `wp.blocks`, and `wp.components`. Each of these need to be included in the array of dependencies. Update the `myguten-meta-block.php` file adding the enqueue function: +**Important:** Before you test, you need to enqueue your JavaScript file and its dependencies. Note the WordPress packages used above are `wp.element`, `wp.blocks`, `wp.components`, `wp.data`, and `wp.coreData`. Each of these need to be included in the array of dependencies. Update the `myguten-meta-block.php` file adding the enqueue function: ```php function myguten_enqueue() { wp_enqueue_script( 'myguten-script', plugins_url( 'myguten.js', __FILE__ ), - array( 'wp-blocks', 'wp-element', 'wp-components' ) + array( 'wp-blocks', 'wp-element', 'wp-components', 'wp-data', 'wp-core-data' ) ); } add_action( 'enqueue_block_editor_assets', 'myguten_enqueue' ); @@ -119,4 +137,3 @@ You can now edit a draft post and add a Meta Block to the post. You will see you ![Meta Block](https://raw.githubusercontent.com/WordPress/gutenberg/master/docs/designers-developers/developers/tutorials/metabox/meta-block.png) You can now use the post meta data in a template, or another block. See next section for [using post meta data](/docs/designers-developers/developers/tutorials/metabox/meta-block-4-use-data.md). You could also confirm the data is saved by checking the database table `wp_postmeta` and confirm the new post id contains the new field data. - diff --git a/docs/designers-developers/developers/tutorials/metabox/meta-block-4-use-data.md b/docs/designers-developers/developers/tutorials/metabox/meta-block-4-use-data.md index 6e7d5b92d4d405..e10049e16c2b90 100644 --- a/docs/designers-developers/developers/tutorials/metabox/meta-block-4-use-data.md +++ b/docs/designers-developers/developers/tutorials/metabox/meta-block-4-use-data.md @@ -25,7 +25,7 @@ You can also use the post meta data in other blocks. For this example the data i In PHP, use the [register_block_type](https://developer.wordpress.org/reference/functions/register_block_type/) function to set a callback when the block is rendered to include the meta value. ```php -function myguten_render_paragraph( $attributes, $content ) { +function myguten_render_paragraph( $block, $content ) { $value = get_post_meta( get_the_ID(), 'myguten_meta_block_field', true ); // check value is set before outputting if ( $value ) { diff --git a/docs/designers-developers/glossary.md b/docs/designers-developers/glossary.md index 876bd077e75547..5a53c51bf2f5fb 100644 --- a/docs/designers-developers/glossary.md +++ b/docs/designers-developers/glossary.md @@ -19,8 +19,8 @@
Block name
A unique identifier for a block type, consisting of a plugin-specific namespace and a short label describing the block's intent. e.g. core/image
-
Block patterns
-
Block patterns are predefined layouts of blocks that can be inserted as starter content that are meant to be changed by the user every time. Once inserted, they exist as a local save and are not global.
+
Patterns
+
Patterns are predefined layouts of blocks that can be inserted as starter content that are meant to be changed by the user every time. Once inserted, they exist as a local save and are not global.
Block type
In contrast with the blocks composing a particular post, a block type describes the blueprint by which any block of that type should behave. So while there may be many images within a post, each behaves consistent with a unified image block type definition.
@@ -59,7 +59,7 @@
A set of button controls. In the context of a block, usually referring to the toolbar of block controls shown above the selected block.
Template
-
A template is a pre-defined arrangement of blocks, possibly with predefined attributes or placeholder content. You can provide a template for a post type, to give users a starting point when creating a new piece of content, or inside a custom block with the InnerBlocks component. See the templates documentation for more information. See templates documentation for more information.
+
A template is a pre-defined arrangement of blocks, possibly with predefined attributes or placeholder content. You can provide a template for a post type, to give users a starting point when creating a new piece of content, or inside a custom block with the InnerBlocks component. See the templates documentation for more information.
Template part
Template parts are equivalent – in blocks – of theme template parts. They are generally defined by a theme first. They carry some semantic meaning (could be swapped between themes such as a header) and can only be inserted in the site editor context (within β€œtemplates”). They are primarily site structure and are never to be mixed with the post content editor.
diff --git a/docs/manifest.json b/docs/manifest.json index 2f124ea2c896eb..7e5cac22e042e5 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -71,6 +71,12 @@ "markdown_source": "../docs/designers-developers/developers/block-api/block-attributes.md", "parent": "block-api" }, + { + "title": "Block Context", + "slug": "block-context", + "markdown_source": "../docs/designers-developers/developers/block-api/block-context.md", + "parent": "block-api" + }, { "title": "Deprecated Blocks", "slug": "block-deprecation", @@ -83,6 +89,12 @@ "markdown_source": "../docs/designers-developers/developers/block-api/block-templates.md", "parent": "block-api" }, + { + "title": "Patterns (Experimental)", + "slug": "block-patterns", + "markdown_source": "../docs/designers-developers/developers/block-api/block-patterns.md", + "parent": "block-api" + }, { "title": "Annotations", "slug": "block-annotations", @@ -264,9 +276,9 @@ "parent": "designers" }, { - "title": "Patterns", - "slug": "design-patterns", - "markdown_source": "../docs/designers-developers/designers/design-patterns.md", + "title": "User Interface", + "slug": "user-interface", + "markdown_source": "../docs/designers-developers/designers/user-interface.md", "parent": "designers" }, { @@ -377,6 +389,12 @@ "markdown_source": "../docs/contributors/copy-guide.md", "parent": "document" }, + { + "title": "Triage", + "slug": "triage", + "markdown_source": "../docs/contributors/triage.md", + "parent": "contributors" + }, { "title": "Localizing Gutenberg Plugin", "slug": "localizing", @@ -887,6 +905,12 @@ "markdown_source": "../packages/components/src/notice/README.md", "parent": "components" }, + { + "title": "NumberControl", + "slug": "number-control", + "markdown_source": "../packages/components/src/number-control/README.md", + "parent": "components" + }, { "title": "Panel", "slug": "panel", @@ -917,6 +941,12 @@ "markdown_source": "../packages/components/src/radio-control/README.md", "parent": "components" }, + { + "title": "RadioGroup", + "slug": "radio-group", + "markdown_source": "../packages/components/src/radio-group/README.md", + "parent": "components" + }, { "title": "RangeControl", "slug": "range-control", @@ -1025,6 +1055,12 @@ "markdown_source": "../packages/components/src/tree-select/README.md", "parent": "components" }, + { + "title": "UnitControl", + "slug": "unit-control", + "markdown_source": "../packages/components/src/unit-control/README.md", + "parent": "components" + }, { "title": "VisuallyHidden", "slug": "visually-hidden", @@ -1283,6 +1319,12 @@ "markdown_source": "../packages/e2e-tests/README.md", "parent": "packages" }, + { + "title": "@wordpress/edit-navigation", + "slug": "packages-edit-navigation", + "markdown_source": "../packages/edit-navigation/README.md", + "parent": "packages" + }, { "title": "@wordpress/edit-post", "slug": "packages-edit-post", @@ -1361,6 +1403,12 @@ "markdown_source": "../packages/icons/README.md", "parent": "packages" }, + { + "title": "@wordpress/interface", + "slug": "packages-interface", + "markdown_source": "../packages/interface/README.md", + "parent": "packages" + }, { "title": "@wordpress/is-shallow-equal", "slug": "packages-is-shallow-equal", diff --git a/docs/rfc/block-registration.md b/docs/rfc/block-registration.md index c1844e1646a42f..9ae9d5ad4b1de5 100644 --- a/docs/rfc/block-registration.md +++ b/docs/rfc/block-registration.md @@ -32,7 +32,7 @@ Initial support for server-defined block attributes was merged as part of [#2529 A demonstration for how block registration could be made filterable in PHP was explored in [#5802](https://github.com/WordPress/gutenberg/pull/5802). The purpose here was to explore how plugins could have better control over the registration. -Another exploration in [#5652](https://github.com/WordPress/gutenberg/pull/5652) considered using JSON as a file format to share block type definitions between JavaScript and PHP. +Another exploration in [#5652](https://github.com/WordPress/gutenberg/pull/5652) considered using JSON as a file format to share block type definitions between JavaScript and PHP. ### Conclusions @@ -77,8 +77,8 @@ To register a new block type, start by creating a `block.json` file. This file: "selector": ".message" } }, - "styleVariations": [ - { "name": "default", "label": "Default", "isDefault": true }, + "styleVariations": [ + { "name": "default", "label": "Default", "isDefault": true }, { "name": "other", "label": "Other" } ], "editorScript": "build/editor.js", @@ -222,7 +222,7 @@ The [gettext](https://www.gnu.org/software/gettext/) text domain of the plugin/b * Property: `attributes` ```json -{ +{ "attributes": { "cover": { "type": "string", @@ -252,9 +252,9 @@ See the [the attributes documentation](/docs/designers-developers/developers/blo * Alias: `styleVariations` ```json -{ - "styleVariations": [ - { "name": "default", "label": "Default", "isDefault": true }, +{ + "styleVariations": [ + { "name": "default", "label": "Default", "isDefault": true }, { "name": "other", "label": "Other" } ] } @@ -326,7 +326,7 @@ The following properties are going to be supported for backward compatibility re - `supports` - see the [block supports](/docs/designers-developers/developers/block-api/block-registration.md#supports-optional) documentation page for more details. - `merge` - undocumented as of today. Its role is to handle merging multiple blocks into one. - `getEditWrapperProps` - undocumented as well. Its role is to inject additional props to the block edit's component wrapper. - + **Example**: ```js wp.blocks.registerBlockType( 'my-block/name', { @@ -340,7 +340,7 @@ wp.blocks.registerBlockType( 'my-block/name', { html: false } } ); -``` +``` In the case of [dynamic blocks](/docs/designers-developers/developers/tutorials/block-tutorial/creating-dynamic-blocks.md) supported by WordPress, it should be still possible to register `render_callback` property using [`register_block_type`](https://developer.wordpress.org/reference/functions/register_block_type/) function on the server. @@ -365,31 +365,35 @@ That's why, the `WPDefinedAsset` type has to offer a way to mirror also the shap It's possible to provide an object which takes the following shape: - `handle` (`string`) - the name of the script. If omitted, it will be auto-generated. -- `dependencies` (`string[]`) - an array of registered script handles this script depends on. Default value: `[]`. +- `dependencies` (`string[]`) - an array of registered script handles this script depends on. Default value: `[]`. - `version` (`string`|`false`|`null`) - string specifying the script version number, if it has one, which is added to the URL as a query string for cache busting purposes. If the version is set to `false`, a version number is automatically added equal to current installed WordPress version. If set to `null`, no version is added. Default value: `false`. -The definition is stored inside separate JSON file which ends with `.asset.json` and is located next to the JS/CSS file listed in `block.json`. WordPress will automatically detect this file through pattern matching. This option is the preferred one as it is expected it will become an option to auto-generate those asset files with `@wordpress/scripts` package. +The definition is stored inside separate PHP file which ends with `.asset.php` and is located next to the JS/CSS file listed in `block.json`. WordPress will automatically detect this file through pattern matching. This option is the preferred one as it is expected it will become an option to auto-generate those asset files with `@wordpress/scripts` package. **Example:** ``` build/ -β”œβ”€ editor.js -└─ editor.asset.json +β”œβ”€ index.js +└─ index.asset.php ``` In `block.json`: ```json -{ "editorScript": "build/editor.js" } +{ "editorScript": "build/index.js" } ``` -In `build/editor.asset.json`: -```json -{ - "handle": "my-plugin-notice-editor", - "dependencies": [ "wp-blocks","wp-element", "wp-i18n" ], - "version": "3.0.0" -} +In `build/index.asset.php`: +```php + array( + 'wp-blocks', + 'wp-element', + 'wp-i18n', + ), + 'version' => '3be55b05081a63d8f9d0ecb466c42cfd', +); ``` ## Internationalization @@ -432,6 +436,28 @@ $metadata = array( Implementation should follow the existing [get_plugin_data](https://codex.wordpress.org/Function_Reference/get_plugin_data) function which parses the plugin contents to retrieve the plugin’s metadata, and it applies translations dynamically. +## Server-side registration + +There is also a new API method proposed `register_block_type_from_metadata` that aims to simplify the block type registration on the server from metadata stored in the `block.json` file. This function is going to handle also all necessary work to make internationalization work seamlessly for metadata defined. + +This function takes two params: +- `$path` (`string`) – path to the folder where the `block.json` file is located. +- `$args` (`array`) – an optional array of block type arguments. Default value: `[]`. Any arguments may be defined. However, the one described below is supported by default: + - `$render_callback` (`callable`) – callback used to render blocks of this block type. + +It returns the registered block type (`WP_Block_Type`) on success or `false` on failure. + +**Example:** + +```php +register_block_type_from_metadata( + __DIR__ . '/shortcode', + array( + 'render_callback' => 'render_block_core_shortcode', + ) +); +``` + ## Backward Compatibility The existing registration mechanism (both server side and frontend) will continue to work, it will serve as low-level implementation detail for the `block.json` based registration. diff --git a/docs/toc.json b/docs/toc.json index c369873791bd9c..3c3269200af2aa 100644 --- a/docs/toc.json +++ b/docs/toc.json @@ -13,8 +13,10 @@ { "docs/designers-developers/developers/block-api/block-registration.md": [] }, { "docs/designers-developers/developers/block-api/block-edit-save.md": [] }, { "docs/designers-developers/developers/block-api/block-attributes.md": [] }, - {"docs/designers-developers/developers/block-api/block-deprecation.md": [] }, + { "docs/designers-developers/developers/block-api/block-context.md": [] }, + { "docs/designers-developers/developers/block-api/block-deprecation.md": [] }, { "docs/designers-developers/developers/block-api/block-templates.md": [] }, + { "docs/designers-developers/developers/block-api/block-patterns.md": [] }, { "docs/designers-developers/developers/block-api/block-annotations.md": [] } ] }, { "docs/designers-developers/developers/filters/README.md": [ @@ -53,7 +55,7 @@ ] }, { "docs/designers-developers/designers/README.md": [ { "docs/designers-developers/designers/block-design.md": [] }, - { "docs/designers-developers/designers/design-patterns.md": [] }, + { "docs/designers-developers/designers/user-interface.md": [] }, { "docs/designers-developers/designers/design-resources.md": [] }, { "docs/designers-developers/designers/animation.md": [] } ] }, @@ -76,6 +78,7 @@ { "docs/contributors/document.md": [ { "docs/contributors/copy-guide.md": [] } ] }, + { "docs/contributors/triage.md": [] }, { "docs/contributors/localizing.md": [] }, { "docs/contributors/repository-management.md": [] } ] }, diff --git a/docs/tool/are-data-files-unstaged.js b/docs/tool/are-data-files-unstaged.js deleted file mode 100644 index 38f659ec9bb0c7..00000000000000 --- a/docs/tool/are-data-files-unstaged.js +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env node - -/** - * Node dependencies. - */ -const chalk = require( 'chalk' ); -const execSync = require( 'child_process' ).execSync; - -/** - * Local dependencies. - */ -const getPackages = require( './packages' ); - -const getUnstagedFiles = () => - execSync( 'git diff --name-only', { encoding: 'utf8' } ) - .split( '\n' ) - .filter( ( element ) => '' !== element ); -const readmeFiles = getPackages().map( - ( [ packageName ] ) => - `docs/designers-developers/developers/data/data-${ packageName.replace( - '/', - '-' - ) }.md` -); -const unstagedReadmes = getUnstagedFiles().filter( ( element ) => - readmeFiles.includes( element ) -); - -if ( unstagedReadmes.length > 0 ) { - process.exitCode = 1; - process.stdout.write( - chalk.red( - '\n', - 'Some API docs may be out of date:', - unstagedReadmes.toString(), - 'Either stage them or continue with --no-verify.', - '\n' - ) - ); -} diff --git a/docs/tool/index.js b/docs/tool/index.js index f0b1297f987dfb..d7e03d00974b3b 100644 --- a/docs/tool/index.js +++ b/docs/tool/index.js @@ -2,8 +2,6 @@ * Node dependencies */ const fs = require( 'fs' ); -const { join } = require( 'path' ); -const { execFileSync } = require( 'child_process' ); const path = require( 'path' ); /** @@ -14,9 +12,6 @@ const { getRootManifest } = require( './manifest' ); const tocFileInput = path.resolve( __dirname, '../toc.json' ); const manifestOutput = path.resolve( __dirname, '../manifest.json' ); -// Update data files from code -execFileSync( 'node', [ join( __dirname, 'update-data.js' ) ] ); - // Process TOC file and generate manifest handbook fs.writeFileSync( manifestOutput, diff --git a/docs/tool/packages.js b/docs/tool/packages.js deleted file mode 100644 index 558a3e62c43c23..00000000000000 --- a/docs/tool/packages.js +++ /dev/null @@ -1,39 +0,0 @@ -const packages = [ - [ - 'core', - { - 'Autogenerated actions': 'packages/core-data/src/actions.js', - 'Autogenerated selectors': 'packages/core-data/src/selectors.js', - }, - ], - 'core/annotations', - 'core/blocks', - 'core/block-editor', - 'core/editor', - 'core/edit-post', - 'core/keyboard-shortcuts', - 'core/notices', - 'core/nux', - 'core/viewport', -]; - -module.exports = function() { - return packages.map( ( entry ) => { - if ( ! Array.isArray( entry ) ) { - entry = [ - entry, - { - 'Autogenerated actions': `packages/${ entry.replace( - 'core/', - '' - ) }/src/store/actions.js`, - 'Autogenerated selectors': `packages/${ entry.replace( - 'core/', - '' - ) }/src/store/selectors.js`, - }, - ]; - } - return entry; - } ); -}; diff --git a/docs/tool/update-data.js b/docs/tool/update-data.js deleted file mode 100644 index 89f0fc614f1c50..00000000000000 --- a/docs/tool/update-data.js +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Node dependencies. - */ -const { join } = require( 'path' ); -const spawnSync = require( 'child_process' ).spawnSync; - -/** - * Local dependencies. - */ -const getPackages = require( './packages' ); - -getPackages().forEach( ( entry ) => { - const [ packageName, targetFiles ] = entry; - - Object.entries( targetFiles ).forEach( ( [ token, target ] ) => { - // Note that this needs to be a sync process for each output file that is updated: - // until docgen provides a way to update many tokens at once, we need to make sure - // the output file is updated before starting the second pass for the next token. - const { status, stderr } = spawnSync( - join( - __dirname, - '..', - '..', - 'node_modules', - '.bin', - 'docgen' - ).replace( / /g, '\\ ' ), - [ - target, - `--output docs/designers-developers/developers/data/data-${ packageName.replace( - '/', - '-' - ) }.md`, - '--to-token', - `--use-token "${ token }"`, - '--ignore "/unstable|experimental/i"', - ], - { shell: true } - ); - - if ( status !== 0 ) { - process.stderr.write( `${ packageName } ${ stderr.toString() }\n` ); - process.exit( 1 ); - } - } ); -} ); diff --git a/gutenberg.php b/gutenberg.php index 04e5abe780f13c..e8143a9a355f27 100644 --- a/gutenberg.php +++ b/gutenberg.php @@ -3,7 +3,7 @@ * Plugin Name: Gutenberg * Plugin URI: https://github.com/WordPress/gutenberg * Description: Printing since 1440. This is the development plugin for the new block editor in core. - * Version: 7.7.1 + * Version: 7.9.1 * Author: Gutenberg Team * Text Domain: gutenberg * @@ -54,14 +54,24 @@ function gutenberg_menu() { 'the_gutenberg_widgets' ); } - if ( array_key_exists( 'gutenberg-full-site-editing', get_option( 'gutenberg-experiments' ) ) ) { + if ( array_key_exists( 'gutenberg-navigation', get_option( 'gutenberg-experiments' ) ) ) { add_submenu_page( 'gutenberg', + __( 'Navigation (beta)', 'gutenberg' ), + __( 'Navigation (beta)', 'gutenberg' ), + 'edit_theme_options', + 'gutenberg-navigation', + 'gutenberg_navigation_page' + ); + } + if ( array_key_exists( 'gutenberg-full-site-editing', get_option( 'gutenberg-experiments' ) ) ) { + add_menu_page( __( 'Site Editor (beta)', 'gutenberg' ), __( 'Site Editor (beta)', 'gutenberg' ), 'edit_theme_options', 'gutenberg-edit-site', - 'gutenberg_edit_site_page' + 'gutenberg_edit_site_page', + 'dashicons-layout' ); } } diff --git a/lib/class-wp-block.php b/lib/class-wp-block.php new file mode 100644 index 00000000000000..4e3cf5f17989d0 --- /dev/null +++ b/lib/class-wp-block.php @@ -0,0 +1,240 @@ + testing..." -> "Just testing..." + * + * @var string + */ + public $inner_html = ''; + + /** + * List of string fragments and null markers where inner blocks were found + * + * @example array( + * 'inner_html' => 'BeforeInnerAfter', + * 'inner_blocks' => array( block, block ), + * 'inner_content' => array( 'Before', null, 'Inner', null, 'After' ), + * ) + * + * @var array + */ + public $inner_content = array(); + + /** + * Constructor. + * + * Populates object properties from the provided block instance argument. + * + * The given array of context values will not necessarily be available on + * the instance itself, but is treated as the full set of values provided by + * the block's ancestry. This is assigned to the private `available_context` + * property. Only values which are configured to consumed by the block via + * its registered type will be assigned to the block's `context` property. + * + * @param array $block Array of parsed block properties. + * @param array $available_context Optional array of ancestry context values. + * @param WP_Block_Type_Registry $registry Optional block type registry. + */ + public function __construct( $block, $available_context = array(), $registry = null ) { + $this->name = $block['blockName']; + + if ( is_null( $registry ) ) { + $registry = WP_Block_Type_Registry::get_instance(); + } + + $this->block_type = $registry->get_registered( $this->name ); + + if ( ! empty( $block['attrs'] ) ) { + $this->attributes = $block['attrs']; + } + + if ( ! is_null( $this->block_type ) ) { + $this->attributes = $this->block_type->prepare_attributes_for_render( $this->attributes ); + } + + $this->available_context = $available_context; + + if ( ! empty( $this->block_type->context ) ) { + foreach ( $this->block_type->context as $context_name ) { + if ( array_key_exists( $context_name, $this->available_context ) ) { + $this->context[ $context_name ] = $this->available_context[ $context_name ]; + } + } + } + + if ( ! empty( $block['innerBlocks'] ) ) { + $child_context = $this->available_context; + + /* phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase */ + if ( ! empty( $this->block_type->providesContext ) ) { + foreach ( $this->block_type->providesContext as $context_name => $attribute_name ) { + if ( array_key_exists( $attribute_name, $this->attributes ) ) { + $child_context[ $context_name ] = $this->attributes[ $attribute_name ]; + } + } + } + /* phpcs:enable */ + + $this->inner_blocks = array_map( + function( $inner_block ) use ( $child_context, $registry ) { + return new WP_Block( $inner_block, $child_context, $registry ); + }, + $block['innerBlocks'] + ); + } + + if ( ! empty( $block['innerHTML'] ) ) { + $this->inner_html = $block['innerHTML']; + } + + if ( ! empty( $block['innerContent'] ) ) { + $this->inner_content = $block['innerContent']; + } + } + + /** + * Generates the render output for the block. + * + * @return string Rendered block output. + */ + public function render() { + global $post; + + $is_dynamic = $this->name && null !== $this->block_type && $this->block_type->is_dynamic(); + $block_content = ''; + + $index = 0; + foreach ( $this->inner_content as $chunk ) { + $block_content .= is_string( $chunk ) ? + $chunk : + $this->inner_blocks[ $index++ ]->render(); + } + + if ( $is_dynamic ) { + $global_post = $post; + $block_content = (string) call_user_func( $this->block_type->render_callback, $this, $block_content ); + $post = $global_post; + } + + return $block_content; + } + + /** + * Returns true if an attribute exists by the specified attribute name, or + * false otherwise. + * + * @link https://www.php.net/manual/en/arrayaccess.offsetexists.php + * + * @param string $attribute_name Name of attribute to check. + * + * @return bool Whether attribute exists. + */ + public function offsetExists( $attribute_name ) { + return isset( $this->attributes[ $attribute_name ] ); + } + + /** + * Returns the value by the specified attribute name. + * + * @link https://www.php.net/manual/en/arrayaccess.offsetget.php + * + * @param string $attribute_name Name of attribute value to retrieve. + * + * @return mixed|null Attribute value if exists, or null. + */ + public function offsetGet( $attribute_name ) { + // This may cause an "Undefined index" notice if the attribute name does + // not exist. This is expected, since the purpose of this implementation + // is to align exactly to the expectations of operating on an array. + return $this->attributes[ $attribute_name ]; + } + + /** + * Assign an attribute value by the specified attribute name. + * + * @link https://www.php.net/manual/en/arrayaccess.offsetset.php + * + * @param string $attribute_name Name of attribute value to set. + * @param mixed $value Attribute value. + */ + public function offsetSet( $attribute_name, $value ) { + if ( is_null( $attribute_name ) ) { + // This is not technically a valid use-case for attributes. Since + // this implementation is expected to align to expectations of + // operating on an array, it is still supported. + $this->attributes[] = $value; + } else { + $this->attributes[ $attribute_name ] = $value; + } + } + + /** + * Unset an attribute. + * + * @link https://www.php.net/manual/en/arrayaccess.offsetunset.php + * + * @param string $attribute_name Name of attribute value to unset. + */ + public function offsetUnset( $attribute_name ) { + unset( $this->attributes[ $attribute_name ] ); + } + +} diff --git a/lib/class-wp-patterns-registry.php b/lib/class-wp-patterns-registry.php new file mode 100644 index 00000000000000..c83ab704de8537 --- /dev/null +++ b/lib/class-wp-patterns-registry.php @@ -0,0 +1,137 @@ +registered_patterns[ $pattern_name ] = $pattern_properties; + + return true; + } + + /** + * Unregisters a pattern. + * + * @param string $pattern_name Pattern name including namespace. + * @return boolean True if the pattern was unregistered with success and false otherwise. + */ + public function unregister( $pattern_name ) { + if ( ! $this->is_registered( $pattern_name ) ) { + /* translators: 1: Pattern name. */ + $message = sprintf( __( 'Pattern "%1$s" not found.', 'gutenberg' ), $pattern_name ); + _doing_it_wrong( __METHOD__, $message, '7.8.0' ); + return false; + } + + unset( $this->registered_patterns[ $pattern_name ] ); + + return true; + } + + /** + * Retrieves an array containing the properties of a registered pattern. + * + * @param string $pattern_name Pattern name including namespace. + * @return array Registered pattern properties. + */ + public function get_registered( $pattern_name ) { + if ( ! $this->is_registered( $pattern_name ) ) { + return null; + } + + return $this->registered_patterns[ $pattern_name ]; + } + + /** + * Retrieves all registered patterns. + * + * @return array Array of arrays containing the registered patterns properties, + * and per style. + */ + public function get_all_registered() { + return array_values( $this->registered_patterns ); + } + + /** + * Checks if a pattern is registered. + * + * @param string $pattern_name Pattern name including namespace. + * @return bool True if the pattern is registered, false otherwise. + */ + public function is_registered( $pattern_name ) { + return isset( $this->registered_patterns[ $pattern_name ] ); + } + + /** + * Utility method to retrieve the main instance of the class. + * + * The instance will be created if it does not exist yet. + * + * @since 5.3.0 + * + * @return WP_Patterns_Registry The main instance. + */ + public static function get_instance() { + if ( null === self::$instance ) { + self::$instance = new self(); + } + + return self::$instance; + } +} + +/** + * Registers a new pattern. + * + * @param string $pattern_name Pattern name including namespace. + * @param array $pattern_properties Array containing the properties of the pattern. + * + * @return boolean True if the pattern was registered with success and false otherwise. + */ +function register_pattern( $pattern_name, $pattern_properties ) { + return WP_Patterns_Registry::get_instance()->register( $pattern_name, $pattern_properties ); +} + +/** + * Unregisters a pattern. + * + * @param string $pattern_name Pattern name including namespace. + * + * @return boolean True if the pattern was unregistered with success and false otherwise. + */ +function unregister_pattern( $pattern_name ) { + return WP_Patterns_Registry::get_instance()->unregister( $pattern_name ); +} diff --git a/lib/class-wp-rest-block-directory-controller.php b/lib/class-wp-rest-block-directory-controller.php index 7360fa9d2533ff..9c2c2f96160cfe 100644 --- a/lib/class-wp-rest-block-directory-controller.php +++ b/lib/class-wp-rest-block-directory-controller.php @@ -303,7 +303,7 @@ private static function parse_block_metadata( $plugin ) { $block->humanized_updated = sprintf( /* translators: %s: Human-readable time difference. */ __( '%s ago', 'gutenberg' ), - human_time_diff( strtotime( $plugin['last_updated'] ), current_time( 'timestamp' ) ) + human_time_diff( strtotime( $plugin['last_updated'] ), time() ) ); return $block; diff --git a/lib/class-wp-rest-menu-items-controller.php b/lib/class-wp-rest-menu-items-controller.php index 18079b23ed711e..cd592046fe661f 100644 --- a/lib/class-wp-rest-menu-items-controller.php +++ b/lib/class-wp-rest-menu-items-controller.php @@ -404,7 +404,7 @@ protected function prepare_item_for_database( $request ) { } elseif ( 'post_type' === $prepared_nav_item['menu-item-type'] ) { $original = get_post( absint( $prepared_nav_item['menu-item-object-id'] ) ); if ( empty( $original ) ) { - return new WP_Error( 'rest_post_invalid_id', __( 'Invalid post ID.', 'gutenberg' ), array( 'status' => 400 ) ); + return new WP_Error( 'rest_post_invalid_id', __( 'Invalid post ID.', 'gutenberg' ), array( 'status' => 400 ) ); } $prepared_nav_item['menu-item-object'] = get_post_type( $original ); } @@ -422,10 +422,10 @@ protected function prepare_item_for_database( $request ) { // Check if menu item is type custom, then title and url are required. if ( 'custom' === $prepared_nav_item['menu-item-type'] ) { if ( '' === $prepared_nav_item['menu-item-title'] ) { - return new WP_Error( 'rest_title_required', __( 'Title require if menu item of type custom.', 'gutenberg' ), array( 'status' => 400 ) ); + return new WP_Error( 'rest_title_required', __( 'Title required if menu item of type custom.', 'gutenberg' ), array( 'status' => 400 ) ); } if ( empty( $prepared_nav_item['menu-item-url'] ) ) { - return new WP_Error( 'rest_url_required', __( 'URL require if menu item of type custom.', 'gutenberg' ), array( 'status' => 400 ) ); + return new WP_Error( 'rest_url_required', __( 'URL required if menu item of type custom.', 'gutenberg' ), array( 'status' => 400 ) ); } } @@ -840,7 +840,7 @@ public function get_item_schema() { ); $schema['properties']['menu_order'] = array( - 'description' => __( 'The DB ID of the nav_menu_item that is this item\'s menu parent, if any . 0 otherwise . ', 'gutenberg' ), + 'description' => __( 'The DB ID of the nav_menu_item that is this item\'s menu parent, if any, otherwise 0.', 'gutenberg' ), 'context' => array( 'view', 'edit', 'embed' ), 'type' => 'integer', 'minimum' => 0, @@ -853,7 +853,7 @@ public function get_item_schema() { ); $schema['properties']['object_id'] = array( - 'description' => __( 'The DB ID of the original object this menu item represents, e . g . ID for posts and term_id for categories .', 'gutenberg' ), + 'description' => __( 'The DB ID of the original object this menu item represents, e . g . ID for posts and term_id for categories.', 'gutenberg' ), 'context' => array( 'view', 'edit', 'embed' ), 'type' => 'integer', 'minimum' => 0, @@ -899,7 +899,7 @@ public function get_item_schema() { ); $schema['properties']['_invalid'] = array( - 'description' => __( 'Whether the menu item represents an object that no longer exists .', 'gutenberg' ), + 'description' => __( 'Whether the menu item represents an object that no longer exists.', 'gutenberg' ), 'context' => array( 'view', 'edit', 'embed' ), 'type' => 'boolean', 'readonly' => true, diff --git a/lib/client-assets.php b/lib/client-assets.php index e90d5afa026d46..4a0b6c3824f1d0 100644 --- a/lib/client-assets.php +++ b/lib/client-assets.php @@ -396,6 +396,15 @@ function gutenberg_register_packages_styles( &$styles ) { ); $styles->add_data( 'wp-list-reusable-block', 'rtl', 'replace' ); + gutenberg_override_style( + $styles, + 'wp-edit-navigation', + gutenberg_url( 'build/edit-navigation/style.css' ), + array( 'wp-components', 'wp-block-editor', 'wp-edit-blocks' ), + filemtime( gutenberg_dir_path() . 'build/edit-navigation/style.css' ) + ); + $styles->add_data( 'wp-edit-navigation', 'rtl', 'replace' ); + gutenberg_override_style( $styles, 'wp-edit-site', @@ -432,19 +441,6 @@ function gutenberg_register_packages_styles( &$styles ) { * @since 0.1.0 */ function gutenberg_enqueue_block_editor_assets() { - wp_add_inline_script( - 'wp-api-fetch', - sprintf( - 'wp.apiFetch.nonceMiddleware = wp.apiFetch.createNonceMiddleware( "%s" );' . - 'wp.apiFetch.use( wp.apiFetch.nonceMiddleware );' . - 'wp.apiFetch.nonceEndpoint = "%s";' . - 'wp.apiFetch.use( wp.apiFetch.mediaUploadMiddleware );', - ( wp_installing() && ! is_multisite() ) ? '' : wp_create_nonce( 'wp_rest' ), - admin_url( 'admin-ajax.php?action=gutenberg_rest_nonce' ) - ), - 'after' - ); - if ( defined( 'GUTENBERG_LIVE_RELOAD' ) && GUTENBERG_LIVE_RELOAD ) { $live_reload_url = ( GUTENBERG_LIVE_RELOAD === true ) ? 'http://localhost:35729/livereload.js' : GUTENBERG_LIVE_RELOAD; @@ -640,7 +636,7 @@ function gutenberg_load_block_pattern( $name ) { } /** - * Extends block editor settings to include a list of default block patterns. + * Extends block editor settings to include a list of default patterns. * * @param array $settings Default editor settings. * @@ -648,19 +644,54 @@ function gutenberg_load_block_pattern( $name ) { */ function gutenberg_extend_settings_block_patterns( $settings ) { if ( empty( $settings['__experimentalBlockPatterns'] ) ) { - $settings['__experimentalBlockPatterns'] = []; + $settings['__experimentalBlockPatterns'] = array(); } $settings['__experimentalBlockPatterns'] = array_merge( - [ - gutenberg_load_block_pattern( 'text-two-columns' ), - gutenberg_load_block_pattern( 'two-buttons' ), - gutenberg_load_block_pattern( 'cover-abc' ), - gutenberg_load_block_pattern( 'two-images' ), - ], + WP_Patterns_Registry::get_instance()->get_all_registered(), $settings['__experimentalBlockPatterns'] ); return $settings; } add_filter( 'block_editor_settings', 'gutenberg_extend_settings_block_patterns', 0 ); + +/** + * Extends block editor settings to determine whether to use custom line height controls. + * + * @param array $settings Default editor settings. + * + * @return array Filtered editor settings. + */ +function gutenberg_extend_settings_custom_line_height( $settings ) { + $settings['__experimentalDisableCustomLineHeight'] = get_theme_support( 'disable-custom-line-height' ); + return $settings; +} +add_filter( 'block_editor_settings', 'gutenberg_extend_settings_custom_line_height' ); + +/** + * Extends block editor settings to determine whether to use custom unit controls. + * Currently experimental. + * + * @param array $settings Default editor settings. + * + * @return array Filtered editor settings. + */ +function gutenberg_extend_settings_custom_units( $settings ) { + $settings['__experimentalDisableCustomUnits'] = get_theme_support( 'experimental-custom-units' ); + return $settings; +} +add_filter( 'block_editor_settings', 'gutenberg_extend_settings_custom_units' ); + +/* + * Register default patterns if not registered in Core already. + */ +if ( class_exists( 'WP_Patterns_Registry' ) && ! WP_Patterns_Registry::get_instance()->is_registered( 'text-two-columns' ) ) { + register_pattern( 'core/text-two-columns', gutenberg_load_block_pattern( 'text-two-columns' ) ); + register_pattern( 'core/two-buttons', gutenberg_load_block_pattern( 'two-buttons' ) ); + register_pattern( 'core/cover-abc', gutenberg_load_block_pattern( 'cover-abc' ) ); + register_pattern( 'core/two-images', gutenberg_load_block_pattern( 'two-images' ) ); + register_pattern( 'core/hero-two-columns', gutenberg_load_block_pattern( 'hero-two-columns' ) ); + register_pattern( 'core/numbered-features', gutenberg_load_block_pattern( 'numbered-features' ) ); + register_pattern( 'core/its-time', gutenberg_load_block_pattern( 'its-time' ) ); +} diff --git a/lib/compat.php b/lib/compat.php index 6e68f2134b2cff..96c07375dda41e 100644 --- a/lib/compat.php +++ b/lib/compat.php @@ -8,6 +8,42 @@ * @package gutenberg */ +if ( ! function_exists( 'register_block_type_from_metadata' ) ) { + /** + * Registers a block type from metadata stored in the `block.json` file. + * + * @since 7.9.0 + * + * @param string $path Path to the folder where the `block.json` file is located. + * @param array $args { + * Optional. Array of block type arguments. Any arguments may be defined, however the + * ones described below are supported by default. Default empty array. + * + * @type callable $render_callback Callback used to render blocks of this block type. + * } + * @return WP_Block_Type|false The registered block type on success, or false on failure. + */ + function register_block_type_from_metadata( $path, $args = array() ) { + $file = trailingslashit( $path ) . 'block.json'; + if ( ! file_exists( $file ) ) { + return false; + } + + $metadata = json_decode( file_get_contents( $file ), true ); + if ( ! is_array( $metadata ) ) { + return false; + } + + return register_block_type( + $metadata['name'], + array_merge( + $metadata, + $args + ) + ); + } +} + /** * Extends block editor settings to include a list of image dimensions per size. * @@ -125,3 +161,37 @@ function gutenberg_get_post_from_context() { } return get_post(); } + +/** + * Shim that hooks into `pre_render_block` so as to override `render_block` with + * a function that assigns block context. + * + * This can be removed when plugin support requires WordPress 5.5.0+. + * + * @see (TBD Trac Link) + * + * @param string|null $pre_render The pre-rendered content. Defaults to null. + * @param array $parsed_block The parsed block being rendered. + * + * @return string String of rendered HTML. + */ +function gutenberg_render_block_with_assigned_block_context( $pre_render, $parsed_block ) { + global $post; + + // If a non-null value is provided, a filter has run at an earlier priority + // and has already handled custom rendering and should take precedence. + if ( null !== $pre_render ) { + return $pre_render; + } + + $source_block = $parsed_block; + + /** This filter is documented in src/wp-includes/blocks.php */ + $parsed_block = apply_filters( 'render_block_data', $parsed_block, $source_block ); + $context = array( 'postId' => $post->ID ); + $block = new WP_Block( $parsed_block, $context ); + + /** This filter is documented in src/wp-includes/blocks.php */ + return apply_filters( 'render_block', $block->render(), $parsed_block ); +} +add_filter( 'pre_render_block', 'gutenberg_render_block_with_assigned_block_context', 9, 2 ); diff --git a/lib/edit-site-page.php b/lib/edit-site-page.php index ef24509f5447e6..c9cad42f3360cd 100644 --- a/lib/edit-site-page.php +++ b/lib/edit-site-page.php @@ -28,12 +28,56 @@ class="edit-site" * @return bool True for Site Editor pages, false otherwise. */ function gutenberg_is_edit_site_page( $page ) { - $allowed_pages = array( - 'gutenberg_page_gutenberg-edit-site', - 'toplevel_page_gutenberg-edit-site', + return 'toplevel_page_gutenberg-edit-site' === $page; +} + +/** + * Load editor styles (this is copied form edit-form-blocks.php). + * Ideally the code is extracted into a reusable function. + * + * @return array Editor Styles Setting. + */ +function gutenberg_get_editor_styles() { + global $editor_styles; + + // + // Ideally the code is extracted into a reusable function. + $styles = array( + array( + 'css' => file_get_contents( + ABSPATH . WPINC . '/css/dist/editor/editor-styles.css' + ), + ), + ); + + /* translators: Use this to specify the CSS font family for the default font. */ + $locale_font_family = esc_html_x( 'Noto Serif', 'CSS Font Family for Editor Font', 'gutenberg' ); + $styles[] = array( + 'css' => "body { font-family: '$locale_font_family' }", ); - return in_array( $page, $allowed_pages, true ); + if ( $editor_styles && current_theme_supports( 'editor-styles' ) ) { + foreach ( $editor_styles as $style ) { + if ( preg_match( '~^(https?:)?//~', $style ) ) { + $response = wp_remote_get( $style ); + if ( ! is_wp_error( $response ) ) { + $styles[] = array( + 'css' => wp_remote_retrieve_body( $response ), + ); + } + } else { + $file = get_theme_file_path( $style ); + if ( is_file( $file ) ) { + $styles[] = array( + 'css' => file_get_contents( $file ), + 'baseURL' => get_theme_file_uri( $style ), + ); + } + } + } + } + + return $styles; } /** @@ -152,12 +196,34 @@ function gutenberg_edit_site_init( $hook ) { $settings['templateType'] = 'wp_template'; $settings['templateIds'] = array_values( $template_ids ); $settings['templatePartIds'] = array_values( $template_part_ids ); + $settings['styles'] = gutenberg_get_editor_styles(); // This is so other parts of the code can hook their own settings. // Example: Global Styles. global $post; $settings = apply_filters( 'block_editor_settings', $settings, $post ); + // Preload block editor paths. + // most of these are copied from edit-forms-blocks.php. + $preload_paths = array( + '/', + '/wp/v2/types?context=edit', + '/wp/v2/taxonomies?per_page=-1&context=edit', + '/wp/v2/themes?status=active', + sprintf( '/wp/v2/templates/%s?context=edit', $_wp_current_template_id ), + array( '/wp/v2/media', 'OPTIONS' ), + ); + $preload_data = array_reduce( + $preload_paths, + 'rest_preload_api_request', + array() + ); + wp_add_inline_script( + 'wp-api-fetch', + sprintf( 'wp.apiFetch.use( wp.apiFetch.createPreloadingMiddleware( %s ) );', wp_json_encode( $preload_data ) ), + 'after' + ); + // Initialize editor. wp_add_inline_script( 'wp-edit-site', diff --git a/lib/experiments-page.php b/lib/experiments-page.php index 2d8ac36a2c2569..07a7f2a200a7b3 100644 --- a/lib/experiments-page.php +++ b/lib/experiments-page.php @@ -51,6 +51,17 @@ function gutenberg_initialize_experiments_settings() { 'id' => 'gutenberg-widget-experiments', ) ); + add_settings_field( + 'gutenberg-navigation', + __( 'Navigation', 'gutenberg' ), + 'gutenberg_display_experiment_field', + 'gutenberg-experiments', + 'gutenberg_experiments_section', + array( + 'label' => __( 'Enable Navigation screen', 'gutenberg' ), + 'id' => 'gutenberg-navigation', + ) + ); add_settings_field( 'gutenberg-block-directory', __( 'Block Directory', 'gutenberg' ), diff --git a/lib/load.php b/lib/load.php index f1037f11d36be2..1dca8b64972c56 100644 --- a/lib/load.php +++ b/lib/load.php @@ -59,6 +59,14 @@ function gutenberg_is_experiment_enabled( $name ) { require dirname( __FILE__ ) . '/class-wp-block-styles-registry.php'; } +if ( ! class_exists( 'WP_Patterns_Registry' ) ) { + require dirname( __FILE__ ) . '/class-wp-patterns-registry.php'; +} + +if ( ! class_exists( 'WP_Block' ) ) { + require dirname( __FILE__ ) . '/class-wp-block.php'; +} + require dirname( __FILE__ ) . '/compat.php'; require dirname( __FILE__ ) . '/blocks.php'; @@ -70,6 +78,7 @@ function gutenberg_is_experiment_enabled( $name ) { require dirname( __FILE__ ) . '/demo.php'; require dirname( __FILE__ ) . '/widgets.php'; require dirname( __FILE__ ) . '/widgets-page.php'; +require dirname( __FILE__ ) . '/navigation-page.php'; require dirname( __FILE__ ) . '/experiments-page.php'; require dirname( __FILE__ ) . '/customizer.php'; require dirname( __FILE__ ) . '/edit-site-page.php'; diff --git a/lib/navigation-page.php b/lib/navigation-page.php new file mode 100644 index 00000000000000..74227fcfbd1cd9 --- /dev/null +++ b/lib/navigation-page.php @@ -0,0 +1,101 @@ + + + __( 'Thumbnail', 'gutenberg' ), + 'medium' => __( 'Medium', 'gutenberg' ), + 'large' => __( 'Large', 'gutenberg' ), + 'full' => __( 'Full Size', 'gutenberg' ), + ) + ); + + $available_image_sizes = array(); + foreach ( $image_size_names as $image_size_slug => $image_size_name ) { + $available_image_sizes[] = array( + 'slug' => $image_size_slug, + 'name' => $image_size_name, + ); + } + + $settings = array( + 'disableCustomColors' => get_theme_support( 'disable-custom-colors' ), + 'disableCustomFontSizes' => get_theme_support( 'disable-custom-font-sizes' ), + 'imageSizes' => $available_image_sizes, + 'isRTL' => is_rtl(), + 'maxUploadFileSize' => $max_upload_size, + ); + + list( $color_palette, ) = (array) get_theme_support( 'editor-color-palette' ); + list( $font_sizes, ) = (array) get_theme_support( 'editor-font-sizes' ); + + if ( false !== $color_palette ) { + $settings['colors'] = $color_palette; + } + + if ( false !== $font_sizes ) { + $settings['fontSizes'] = $font_sizes; + } + + wp_add_inline_script( + 'wp-edit-navigation', + sprintf( + 'wp.domReady( function() { + wp.editNavigation.initialize( "navigation-editor", %s ); + } );', + wp_json_encode( gutenberg_experiments_editor_settings( $settings ) ) + ) + ); + + // Preload server-registered block schemas. + wp_add_inline_script( + 'wp-blocks', + 'wp.blocks.unstable__bootstrapServerSideBlockDefinitions(' . wp_json_encode( get_block_editor_server_block_settings() ) . ');' + ); + + wp_enqueue_script( 'wp-edit-navigation' ); + wp_enqueue_style( 'wp-edit-navigation' ); + wp_enqueue_style( 'wp-block-library' ); + wp_enqueue_script( 'wp-format-library' ); + wp_enqueue_style( 'wp-format-library' ); +} +add_action( 'admin_enqueue_scripts', 'gutenberg_navigation_init' ); diff --git a/lib/patterns/hero-two-columns.json b/lib/patterns/hero-two-columns.json new file mode 100644 index 00000000000000..eb1805c3dff0e3 --- /dev/null +++ b/lib/patterns/hero-two-columns.json @@ -0,0 +1,5 @@ +{ + "__file": "wp_block", + "title": "Hero Two Columns", + "content": "\n
\n

Enjoy a wide variety of

\n\n\n\n

Custom Designs

\n\n\n\n
\n
\n

Extend it with over 54,000 plugins to help your website meet your needs. Add an online store, galleries, mailing lists, forums, analytics, and much more. Hundreds of thousands of developers and site owners trust it worldwide.

\n
\n\n\n\n
\n

Hundreds of thousands of developers and site owners trust it worldwide. Extend it with over 54,000 plugins to help your website meet your needs. Add an online store, galleries, mailing lists, forums, analytics, and much more.

\n
\n
\n
\n" + } diff --git a/lib/patterns/its-time.json b/lib/patterns/its-time.json new file mode 100644 index 00000000000000..0e048a908ba568 --- /dev/null +++ b/lib/patterns/its-time.json @@ -0,0 +1,5 @@ +{ + "__file": "wp_block", + "title": "It's time", + "content": "\n
\n
\n
\n

NEW

\n\n\n\n

John Lenwood \"Jackie\" McLean was an American jazz alto saxophonist, composer, bandleader, and educator, and is one of the few musicians to be elected to the DownBeat Hall of Fame in the year of their death.

\n
\n\n\n\n
\n

space

\n\n\n\n

Derek Ansell's full-length biography of McLean, Sugar Free Saxophone (London: Northway Books, 2012), details the story of his career and provides a full analysis of his music on record.

\n
\n
\n\n\n\n
\n
\n\n\n\n
\n

it's time

\n
\n
\n
\n" + } diff --git a/lib/patterns/numbered-features.json b/lib/patterns/numbered-features.json new file mode 100644 index 00000000000000..010a0f52e09ed4 --- /dev/null +++ b/lib/patterns/numbered-features.json @@ -0,0 +1,5 @@ +{ + "__file": "wp_block", + "title": "Numbered Features", + "content": "\n
\n
\n
\n
\n

1

\n
\n\n\n\n
\n

Custom Designs

\n\n\n\n

Extend it with over 54,000 plugins to help your website meet your needs.

\n\n\n\n
\n
\n
\n
\n\n\n\n
\n
\n
\n

2

\n
\n\n\n\n
\n

High Performance

\n\n\n\n

Add an online store, galleries, mailing lists, forums, analytics, and much more.

\n\n\n\n
\n
\n
\n
\n\n\n\n
\n
\n
\n

3

\n
\n\n\n\n
\n

Easy and Accessible

\n\n\n\n

Hundreds of thousands of developers and site owners trust it worldwide.

\n
\n
\n
\n
\n" + } diff --git a/lib/rest-api.php b/lib/rest-api.php index eba3685e4cdd7a..6ca1e10cd00a42 100644 --- a/lib/rest-api.php +++ b/lib/rest-api.php @@ -52,7 +52,41 @@ function gutenberg_filter_oembed_result( $response, $handler, $request ) { } add_filter( 'rest_request_after_callbacks', 'gutenberg_filter_oembed_result', 10, 3 ); +/** + * Add fields required for site editing to the /themes endpoint. + * + * @todo Remove once https://core.trac.wordpress.org/ticket/49906 is fixed. + * @see https://github.com/WordPress/wordpress-develop/pull/222 + * + * @param WP_REST_Response $response The response object. + * @param WP_Theme $theme Theme object used to create response. + * @param WP_REST_Request $request Request object. + */ +function gutenberg_filter_rest_prepare_theme( $response, $theme, $request ) { + $data = $response->get_data(); + $field_mappings = array( + 'author' => 'Author', + 'author_name' => 'Author Name', + 'author_uri' => 'Author URI', + 'description' => 'Description', + 'name' => 'Name', + 'stylesheet' => 'Stylesheet', + 'template' => 'Template', + 'theme_uri' => 'Theme URI', + 'version' => 'Version', + ); + foreach ( $field_mappings as $field => $theme_field ) { + $data[ $field ] = $theme[ $theme_field ]; + } + + // Using $theme->get_screenshot() with no args to get absolute URL. + $data['screenshot'] = $theme->get_screenshot(); + + $response->set_data( $data ); + return $response; +} +add_filter( 'rest_prepare_theme', 'gutenberg_filter_rest_prepare_theme', 10, 3 ); /** * Start: Include for phase 2 diff --git a/lib/template-loader.php b/lib/template-loader.php index 2a103da5019657..0ef843f205bc7d 100644 --- a/lib/template-loader.php +++ b/lib/template-loader.php @@ -155,11 +155,11 @@ function gutenberg_find_template( $template_file ) { 'post_name__in' => $slugs, 'orderby' => 'post_name__in', 'posts_per_page' => 1, + 'no_found_rows' => true, ) ); - $template_posts = $template_query->get_posts(); - $current_template_post = array_shift( $template_posts ); + $current_template_post = $template_query->have_posts() ? $template_query->next_post() : null; // Build map of template slugs to their priority in the current hierarchy. $slug_priorities = array_flip( $slugs ); @@ -167,12 +167,17 @@ function gutenberg_find_template( $template_file ) { // See if there is a theme block template with higher priority than the resolved template post. $higher_priority_block_template_path = null; $higher_priority_block_template_priority = PHP_INT_MAX; - $block_template_files = glob( get_stylesheet_directory() . '/block-templates/*.html' ) ?: array(); + $block_template_files = glob( get_stylesheet_directory() . '/block-templates/*.html' ); + $block_template_files = is_array( $block_template_files ) ? $block_template_files : array(); if ( is_child_theme() ) { - $block_template_files = array_merge( $block_template_files, glob( get_template_directory() . '/block-templates/*.html' ) ?: array() ); + $child_block_template_files = glob( get_template_directory() . '/block-templates/*.html' ); + $child_block_template_files = is_array( $child_block_template_files ) ? $child_block_template_files : array(); + $block_template_files = array_merge( $block_template_files, $child_block_template_files ); } if ( gutenberg_is_experiment_enabled( 'gutenberg-full-site-editing-demo' ) ) { - $block_template_files = array_merge( $block_template_files, glob( dirname( __FILE__ ) . '/demo-block-templates/*.html' ) ?: array() ); + $demo_block_template_files = glob( dirname( __FILE__ ) . '/demo-block-templates/*.html' ); + $demo_block_template_files = is_array( $demo_block_template_files ) ? $demo_block_template_files : array(); + $block_template_files = array_merge( $block_template_files, $demo_block_template_files ); } foreach ( $block_template_files as $path ) { if ( ! isset( $slug_priorities[ basename( $path, '.html' ) ] ) ) { @@ -265,7 +270,11 @@ function gutenberg_render_the_template() { $content = $wp_embed->autoembed( $content ); $content = do_blocks( $content ); $content = wptexturize( $content ); - $content = wp_make_content_images_responsive( $content ); + if ( function_exists( 'wp_filter_content_tags' ) ) { + $content = wp_filter_content_tags( $content ); + } else { + $content = wp_make_content_images_responsive( $content ); + } $content = str_replace( ']]>', ']]>', $content ); // Wrap block template in .wp-site-blocks to allow for specific descendant styles diff --git a/package-lock.json b/package-lock.json index 8d9f828aa7bbcd..9018cd74d8838a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "gutenberg", - "version": "7.7.1", + "version": "7.9.1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -29,50 +29,15 @@ } }, "@babel/compat-data": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.8.1.tgz", - "integrity": "sha512-Z+6ZOXvyOWYxJ50BwxzdhRnRsGST8Y3jaZgxYig575lTjVSs3KtJnmESwZegg6e2Dn0td1eDhoWlp1wI4BTCPw==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.9.0.tgz", + "integrity": "sha512-zeFQrr+284Ekvd9e7KAX954LkapWiOmQtsfHirhxqfdlX6MEC32iRE+pqUGlYIBchdevaCwvzxWGSy/YBNI85g==", "requires": { - "browserslist": "^4.8.2", + "browserslist": "^4.9.1", "invariant": "^2.2.4", "semver": "^5.5.0" }, "dependencies": { - "browserslist": { - "version": "4.8.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.5.tgz", - "integrity": "sha512-4LMHuicxkabIB+n9874jZX/az1IaZ5a+EUuvD7KFOu9x/Bd5YHyO0DIz2ls/Kl8g0ItS4X/ilEgf4T1Br0lgSg==", - "requires": { - "caniuse-lite": "^1.0.30001022", - "electron-to-chromium": "^1.3.338", - "node-releases": "^1.1.46" - } - }, - "caniuse-lite": { - "version": "1.0.30001022", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001022.tgz", - "integrity": "sha512-FjwPPtt/I07KyLPkBQ0g7/XuZg6oUkYBVnPHNj3VHJbOjmmJ/GdSo/GUY6MwINEQvjhP6WZVbX8Tvms8xh0D5A==" - }, - "electron-to-chromium": { - "version": "1.3.340", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.340.tgz", - "integrity": "sha512-hRFBAglhcj5iVYH+o8QU0+XId1WGoc0VGowJB1cuJAt3exHGrivZvWeAO5BRgBZqwZtwxjm8a5MQeGoT/Su3ww==" - }, - "node-releases": { - "version": "1.1.47", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.47.tgz", - "integrity": "sha512-k4xjVPx5FpwBUj0Gw7uvFOTF4Ep8Hok1I6qjwL3pLfwe7Y0REQSAqOwwv9TWBCUtMHxcXfY4PgRLRozcChvTcA==", - "requires": { - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } - } - }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -81,21 +46,22 @@ } }, "@babel/core": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.8.3.tgz", - "integrity": "sha512-4XFkf8AwyrEG7Ziu3L2L0Cv+WyY47Tcsp70JFmpftbAA1K7YL/sgE9jh9HyNj08Y/U50ItUchpN0w6HxAoX1rA==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.9.0.tgz", + "integrity": "sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w==", "requires": { "@babel/code-frame": "^7.8.3", - "@babel/generator": "^7.8.3", - "@babel/helpers": "^7.8.3", - "@babel/parser": "^7.8.3", - "@babel/template": "^7.8.3", - "@babel/traverse": "^7.8.3", - "@babel/types": "^7.8.3", + "@babel/generator": "^7.9.0", + "@babel/helper-module-transforms": "^7.9.0", + "@babel/helpers": "^7.9.0", + "@babel/parser": "^7.9.0", + "@babel/template": "^7.8.6", + "@babel/traverse": "^7.9.0", + "@babel/types": "^7.9.0", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.1", - "json5": "^2.1.0", + "json5": "^2.1.2", "lodash": "^4.17.13", "resolve": "^1.3.2", "semver": "^5.4.1", @@ -119,13 +85,18 @@ } }, "json5": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz", - "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", + "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", "requires": { - "minimist": "^1.2.0" + "minimist": "^1.2.5" } }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -139,11 +110,11 @@ } }, "@babel/generator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.3.tgz", - "integrity": "sha512-WjoPk8hRpDRqqzRpvaR8/gDUPkrnOOeuT2m8cNICJtZH6mwaCo3v0OKMI7Y6SM1pBtyijnLtAL0HDi41pf41ug==", + "version": "7.9.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.9.4.tgz", + "integrity": "sha512-rjP8ahaDy/ouhrvCoU1E5mqaitWrxwuNGU+dy1EpaoK48jZay4MdkskKGIMHLZNewg8sAsqpGSREJwP0zH3YQA==", "requires": { - "@babel/types": "^7.8.3", + "@babel/types": "^7.9.0", "jsesc": "^2.5.1", "lodash": "^4.17.13", "source-map": "^0.5.0" @@ -167,69 +138,47 @@ } }, "@babel/helper-builder-react-jsx": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.8.3.tgz", - "integrity": "sha512-JT8mfnpTkKNCboTqZsQTdGo3l3Ik3l7QIt9hh0O9DYiwVel37VoJpILKM4YFbP2euF32nkQSb+F9cUk9b7DDXQ==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.9.0.tgz", + "integrity": "sha512-weiIo4gaoGgnhff54GQ3P5wsUQmnSwpkvU0r6ZHq6TzoSzKy4JxHEgnxNytaKbov2a9z/CVNyzliuCOUPEX3Jw==", "requires": { - "@babel/types": "^7.8.3", - "esutils": "^2.0.0" + "@babel/helper-annotate-as-pure": "^7.8.3", + "@babel/types": "^7.9.0" } }, - "@babel/helper-call-delegate": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.8.3.tgz", - "integrity": "sha512-6Q05px0Eb+N4/GTyKPPvnkig7Lylw+QzihMpws9iiZQv7ZImf84ZsZpQH7QoWN4n4tm81SnSzPgHw2qtO0Zf3A==", + "@babel/helper-builder-react-jsx-experimental": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-react-jsx-experimental/-/helper-builder-react-jsx-experimental-7.9.0.tgz", + "integrity": "sha512-3xJEiyuYU4Q/Ar9BsHisgdxZsRlsShMe90URZ0e6przL26CCs8NJbDoxH94kKT17PcxlMhsCAwZd90evCo26VQ==", "requires": { - "@babel/helper-hoist-variables": "^7.8.3", - "@babel/traverse": "^7.8.3", - "@babel/types": "^7.8.3" + "@babel/helper-annotate-as-pure": "^7.8.3", + "@babel/helper-module-imports": "^7.8.3", + "@babel/types": "^7.9.0" } }, "@babel/helper-compilation-targets": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.3.tgz", - "integrity": "sha512-JLylPCsFjhLN+6uBSSh3iYdxKdeO9MNmoY96PE/99d8kyBFaXLORtAVhqN6iHa+wtPeqxKLghDOZry0+Aiw9Tw==", + "version": "7.8.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.7.tgz", + "integrity": "sha512-4mWm8DCK2LugIS+p1yArqvG1Pf162upsIsjE7cNBjez+NjliQpVhj20obE520nao0o14DaTnFJv+Fw5a0JpoUw==", "requires": { - "@babel/compat-data": "^7.8.1", - "browserslist": "^4.8.2", + "@babel/compat-data": "^7.8.6", + "browserslist": "^4.9.1", "invariant": "^2.2.4", - "levenary": "^1.1.0", + "levenary": "^1.1.1", "semver": "^5.5.0" }, "dependencies": { - "browserslist": { - "version": "4.8.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.5.tgz", - "integrity": "sha512-4LMHuicxkabIB+n9874jZX/az1IaZ5a+EUuvD7KFOu9x/Bd5YHyO0DIz2ls/Kl8g0ItS4X/ilEgf4T1Br0lgSg==", - "requires": { - "caniuse-lite": "^1.0.30001022", - "electron-to-chromium": "^1.3.338", - "node-releases": "^1.1.46" - } - }, - "caniuse-lite": { - "version": "1.0.30001022", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001022.tgz", - "integrity": "sha512-FjwPPtt/I07KyLPkBQ0g7/XuZg6oUkYBVnPHNj3VHJbOjmmJ/GdSo/GUY6MwINEQvjhP6WZVbX8Tvms8xh0D5A==" - }, - "electron-to-chromium": { - "version": "1.3.340", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.340.tgz", - "integrity": "sha512-hRFBAglhcj5iVYH+o8QU0+XId1WGoc0VGowJB1cuJAt3exHGrivZvWeAO5BRgBZqwZtwxjm8a5MQeGoT/Su3ww==" + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" }, - "node-releases": { - "version": "1.1.47", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.47.tgz", - "integrity": "sha512-k4xjVPx5FpwBUj0Gw7uvFOTF4Ep8Hok1I6qjwL3pLfwe7Y0REQSAqOwwv9TWBCUtMHxcXfY4PgRLRozcChvTcA==", + "levenary": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/levenary/-/levenary-1.1.1.tgz", + "integrity": "sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ==", "requires": { - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } + "leven": "^3.1.0" } }, "semver": { @@ -240,48 +189,26 @@ } }, "@babel/helper-create-class-features-plugin": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.8.3.tgz", - "integrity": "sha512-qmp4pD7zeTxsv0JNecSBsEmG1ei2MqwJq4YQcK3ZWm/0t07QstWfvuV/vm3Qt5xNMFETn2SZqpMx2MQzbtq+KA==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.8.6.tgz", + "integrity": "sha512-klTBDdsr+VFFqaDHm5rR69OpEQtO2Qv8ECxHS1mNhJJvaHArR6a1xTf5K/eZW7eZpJbhCx3NW1Yt/sKsLXLblg==", "requires": { "@babel/helper-function-name": "^7.8.3", "@babel/helper-member-expression-to-functions": "^7.8.3", "@babel/helper-optimise-call-expression": "^7.8.3", "@babel/helper-plugin-utils": "^7.8.3", - "@babel/helper-replace-supers": "^7.8.3", + "@babel/helper-replace-supers": "^7.8.6", "@babel/helper-split-export-declaration": "^7.8.3" } }, "@babel/helper-create-regexp-features-plugin": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.3.tgz", - "integrity": "sha512-Gcsm1OHCUr9o9TcJln57xhWHtdXbA2pgQ58S0Lxlks0WMGNXuki4+GLfX0p+L2ZkINUGZvfkz8rzoqJQSthI+Q==", + "version": "7.8.8", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.8.tgz", + "integrity": "sha512-LYVPdwkrQEiX9+1R29Ld/wTrmQu1SSKYnuOk3g0CkcZMA1p0gsNxJFj/3gBdaJ7Cg0Fnek5z0DsMULePP7Lrqg==", "requires": { + "@babel/helper-annotate-as-pure": "^7.8.3", "@babel/helper-regex": "^7.8.3", - "regexpu-core": "^4.6.0" - }, - "dependencies": { - "regenerate-unicode-properties": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz", - "integrity": "sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA==", - "requires": { - "regenerate": "^1.4.0" - } - }, - "regexpu-core": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.6.0.tgz", - "integrity": "sha512-YlVaefl8P5BnFYOITTNzDvan1ulLOiXJzCNZxduTIosN17b87h3bvG9yHMoHaRuo88H4mQ06Aodj5VtYGGGiTg==", - "requires": { - "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^8.1.0", - "regjsgen": "^0.5.0", - "regjsparser": "^0.6.0", - "unicode-match-property-ecmascript": "^1.0.4", - "unicode-match-property-value-ecmascript": "^1.1.0" - } - } + "regexpu-core": "^4.7.0" } }, "@babel/helper-define-map": { @@ -346,15 +273,16 @@ } }, "@babel/helper-module-transforms": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.8.3.tgz", - "integrity": "sha512-C7NG6B7vfBa/pwCOshpMbOYUmrYQDfCpVL/JCRu0ek8B5p8kue1+BCXpg2vOYs7w5ACB9GTOBYQ5U6NwrMg+3Q==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.9.0.tgz", + "integrity": "sha512-0FvKyu0gpPfIQ8EkxlrAydOWROdHpBmiCiRwLkUiBGhCUPRRbVD2/tm3sFr/c/GWFrQ/ffutGUAnx7V0FzT2wA==", "requires": { "@babel/helper-module-imports": "^7.8.3", + "@babel/helper-replace-supers": "^7.8.6", "@babel/helper-simple-access": "^7.8.3", "@babel/helper-split-export-declaration": "^7.8.3", - "@babel/template": "^7.8.3", - "@babel/types": "^7.8.3", + "@babel/template": "^7.8.6", + "@babel/types": "^7.9.0", "lodash": "^4.17.13" } }, @@ -392,14 +320,14 @@ } }, "@babel/helper-replace-supers": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.8.3.tgz", - "integrity": "sha512-xOUssL6ho41U81etpLoT2RTdvdus4VfHamCuAm4AHxGr+0it5fnwoVdwUJ7GFEqCsQYzJUhcbsN9wB9apcYKFA==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz", + "integrity": "sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA==", "requires": { "@babel/helper-member-expression-to-functions": "^7.8.3", "@babel/helper-optimise-call-expression": "^7.8.3", - "@babel/traverse": "^7.8.3", - "@babel/types": "^7.8.3" + "@babel/traverse": "^7.8.6", + "@babel/types": "^7.8.6" } }, "@babel/helper-simple-access": { @@ -419,6 +347,11 @@ "@babel/types": "^7.8.3" } }, + "@babel/helper-validator-identifier": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.0.tgz", + "integrity": "sha512-6G8bQKjOh+of4PV/ThDm/rRqlU7+IGoJuofpagU5GlEl29Vv0RGqqt86ZGRV8ZuSOY3o+8yXl5y782SMcG7SHw==" + }, "@babel/helper-wrap-function": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.8.3.tgz", @@ -431,29 +364,41 @@ } }, "@babel/helpers": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.8.3.tgz", - "integrity": "sha512-LmU3q9Pah/XyZU89QvBgGt+BCsTPoQa+73RxAQh8fb8qkDyIfeQnmgs+hvzhTCKTzqOyk7JTkS3MS1S8Mq5yrQ==", + "version": "7.9.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.9.2.tgz", + "integrity": "sha512-JwLvzlXVPjO8eU9c/wF9/zOIN7X6h8DYf7mG4CiFRZRvZNKEF5dQ3H3V+ASkHoIB3mWhatgl5ONhyqHRI6MppA==", "requires": { "@babel/template": "^7.8.3", - "@babel/traverse": "^7.8.3", - "@babel/types": "^7.8.3" + "@babel/traverse": "^7.9.0", + "@babel/types": "^7.9.0" } }, "@babel/highlight": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", - "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", + "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", "requires": { + "@babel/helper-validator-identifier": "^7.9.0", "chalk": "^2.0.0", - "esutils": "^2.0.2", "js-tokens": "^4.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } } }, "@babel/parser": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.3.tgz", - "integrity": "sha512-/V72F4Yp/qmHaTALizEm9Gf2eQHV3QyTL3K0cNfijwnMnb1L+LDlAubb/ZnSdGAVzVSWakujHYs1I26x66sMeQ==" + "version": "7.9.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.4.tgz", + "integrity": "sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA==" }, "@babel/plugin-external-helpers": { "version": "7.8.3", @@ -518,10 +463,19 @@ "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" } }, - "@babel/plugin-proposal-object-rest-spread": { + "@babel/plugin-proposal-numeric-separator": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-8qvuPwU/xxUCt78HocNlv0mXXo0wdh9VT1R04WU8HGOfaOob26pF+9P5/lYjN/q7DHOX1bvX60hnhOvuQUJdbA==", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.8.3.tgz", + "integrity": "sha512-jWioO1s6R/R+wEHizfaScNsAx+xKgwTLNXSh7tTC4Usj3ItsPEhYkEpU4h+lpnBwq7NBVOJXfO6cRFYcX69JUQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.9.0.tgz", + "integrity": "sha512-UgqBv6bjq4fDb8uku9f+wcm1J7YxJ5nT7WO/jBr0cl0PLKb7t1O6RNR1kZbjgx2LQtsDI9hwoQVmn0yhXeQyow==", "requires": { "@babel/helper-plugin-utils": "^7.8.3", "@babel/plugin-syntax-object-rest-spread": "^7.8.0" @@ -537,20 +491,20 @@ } }, "@babel/plugin-proposal-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.8.3.tgz", - "integrity": "sha512-QIoIR9abkVn+seDE3OjA08jWcs3eZ9+wJCKSRgo3WdEU2csFYgdScb+8qHB3+WXsGJD55u+5hWCISI7ejXS+kg==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.9.0.tgz", + "integrity": "sha512-NDn5tu3tcv4W30jNhmc2hyD5c56G6cXx4TesJubhxrJeCvuuMpttxr0OnNCqbZGhFjLrg+NIhxxC+BK5F6yS3w==", "requires": { "@babel/helper-plugin-utils": "^7.8.3", "@babel/plugin-syntax-optional-chaining": "^7.8.0" } }, "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.3.tgz", - "integrity": "sha512-1/1/rEZv2XGweRwwSkLpY+s60za9OZ1hJs4YDqFHCw0kYWYwL5IFljVY1MYBL+weT1l9pokDO2uhSTLVxzoHkQ==", + "version": "7.8.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.8.tgz", + "integrity": "sha512-EVhjVsMpbhLw9ZfHWSx2iy13Q8Z/eg8e8ccVWt23sWQK5l1UdkoLJPN5w69UA4uITGBnEZD2JOe4QOHycYKv8A==", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.8.3", + "@babel/helper-create-regexp-features-plugin": "^7.8.8", "@babel/helper-plugin-utils": "^7.8.3" } }, @@ -562,6 +516,14 @@ "@babel/helper-plugin-utils": "^7.8.0" } }, + "@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, "@babel/plugin-syntax-class-properties": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.8.3.tgz", @@ -610,6 +572,14 @@ "@babel/helper-plugin-utils": "^7.8.3" } }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.8.3.tgz", + "integrity": "sha512-Zpg2Sgc++37kuFl6ppq2Q7Awc6E6AIW671x5PY8E/f7MCIyPPGK/EoeZXvvY3P42exZ3Q4/t3YOzP/HiN79jDg==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, "@babel/plugin-syntax-nullish-coalescing-operator": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", @@ -618,6 +588,14 @@ "@babel/helper-plugin-utils": "^7.8.0" } }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.8.3.tgz", + "integrity": "sha512-H7dCMAdN83PcCmqmkHB5dtp+Xa9a6LKSvA2hiFBC/5alSHxM5VgWZXFqDi0YFe8XNGT6iCa+z4V4zSt/PdZ7Dw==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, "@babel/plugin-syntax-object-rest-spread": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", @@ -694,16 +672,16 @@ } }, "@babel/plugin-transform-classes": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.8.3.tgz", - "integrity": "sha512-SjT0cwFJ+7Rbr1vQsvphAHwUHvSUPmMjMU/0P59G8U2HLFqSa082JO7zkbDNWs9kH/IUqpHI6xWNesGf8haF1w==", + "version": "7.9.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.9.2.tgz", + "integrity": "sha512-TC2p3bPzsfvSsqBZo0kJnuelnoK9O3welkUpqSqBQuBF6R5MN2rysopri8kNvtlGIb2jmUO7i15IooAZJjZuMQ==", "requires": { "@babel/helper-annotate-as-pure": "^7.8.3", "@babel/helper-define-map": "^7.8.3", "@babel/helper-function-name": "^7.8.3", "@babel/helper-optimise-call-expression": "^7.8.3", "@babel/helper-plugin-utils": "^7.8.3", - "@babel/helper-replace-supers": "^7.8.3", + "@babel/helper-replace-supers": "^7.8.6", "@babel/helper-split-export-declaration": "^7.8.3", "globals": "^11.1.0" }, @@ -724,9 +702,9 @@ } }, "@babel/plugin-transform-destructuring": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.8.3.tgz", - "integrity": "sha512-H4X646nCkiEcHZUZaRkhE2XVsoz0J/1x3VVujnn96pSoGCtKPA99ZZA+va+gK+92Zycd6OBKCD8tDb/731bhgQ==", + "version": "7.8.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.8.8.tgz", + "integrity": "sha512-eRJu4Vs2rmttFCdhPUM3bV0Yo/xPSdPw6ML9KHs/bjB4bLA5HXlbvYXPOD5yASodGod+krjYx21xm1QmL8dCJQ==", "requires": { "@babel/helper-plugin-utils": "^7.8.3" } @@ -758,18 +736,18 @@ } }, "@babel/plugin-transform-flow-strip-types": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.8.3.tgz", - "integrity": "sha512-g/6WTWG/xbdd2exBBzMfygjX/zw4eyNC4X8pRaq7aRHRoDUCzAIu3kGYIXviOv8BjCuWm8vDBwjHcjiRNgXrPA==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.9.0.tgz", + "integrity": "sha512-7Qfg0lKQhEHs93FChxVLAvhBshOPQDtJUTVHr/ZwQNRccCm4O9D79r9tVSoV8iNwjP1YgfD+e/fgHcPkN1qEQg==", "requires": { "@babel/helper-plugin-utils": "^7.8.3", "@babel/plugin-syntax-flow": "^7.8.3" } }, "@babel/plugin-transform-for-of": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.8.3.tgz", - "integrity": "sha512-ZjXznLNTxhpf4Q5q3x1NsngzGA38t9naWH8Gt+0qYZEJAcvPI9waSStSh56u19Ofjr7QmD0wUsQ8hw8s/p1VnA==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.9.0.tgz", + "integrity": "sha512-lTAnWOpMwOXpyDx06N+ywmF3jNbafZEqZ96CGYabxHrxNX8l5ny7dt4bK/rGwAh9utyP2b2Hv7PlZh1AAS54FQ==", "requires": { "@babel/helper-plugin-utils": "^7.8.3" } @@ -800,43 +778,43 @@ } }, "@babel/plugin-transform-modules-amd": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.8.3.tgz", - "integrity": "sha512-MadJiU3rLKclzT5kBH4yxdry96odTUwuqrZM+GllFI/VhxfPz+k9MshJM+MwhfkCdxxclSbSBbUGciBngR+kEQ==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.9.0.tgz", + "integrity": "sha512-vZgDDF003B14O8zJy0XXLnPH4sg+9X5hFBBGN1V+B2rgrB+J2xIypSN6Rk9imB2hSTHQi5OHLrFWsZab1GMk+Q==", "requires": { - "@babel/helper-module-transforms": "^7.8.3", + "@babel/helper-module-transforms": "^7.9.0", "@babel/helper-plugin-utils": "^7.8.3", "babel-plugin-dynamic-import-node": "^2.3.0" } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.8.3.tgz", - "integrity": "sha512-JpdMEfA15HZ/1gNuB9XEDlZM1h/gF/YOH7zaZzQu2xCFRfwc01NXBMHHSTT6hRjlXJJs5x/bfODM3LiCk94Sxg==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.9.0.tgz", + "integrity": "sha512-qzlCrLnKqio4SlgJ6FMMLBe4bySNis8DFn1VkGmOcxG9gqEyPIOzeQrA//u0HAKrWpJlpZbZMPB1n/OPa4+n8g==", "requires": { - "@babel/helper-module-transforms": "^7.8.3", + "@babel/helper-module-transforms": "^7.9.0", "@babel/helper-plugin-utils": "^7.8.3", "@babel/helper-simple-access": "^7.8.3", "babel-plugin-dynamic-import-node": "^2.3.0" } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.8.3.tgz", - "integrity": "sha512-8cESMCJjmArMYqa9AO5YuMEkE4ds28tMpZcGZB/jl3n0ZzlsxOAi3mC+SKypTfT8gjMupCnd3YiXCkMjj2jfOg==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.9.0.tgz", + "integrity": "sha512-FsiAv/nao/ud2ZWy4wFacoLOm5uxl0ExSQ7ErvP7jpoihLR6Cq90ilOFyX9UXct3rbtKsAiZ9kFt5XGfPe/5SQ==", "requires": { "@babel/helper-hoist-variables": "^7.8.3", - "@babel/helper-module-transforms": "^7.8.3", + "@babel/helper-module-transforms": "^7.9.0", "@babel/helper-plugin-utils": "^7.8.3", "babel-plugin-dynamic-import-node": "^2.3.0" } }, "@babel/plugin-transform-modules-umd": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.8.3.tgz", - "integrity": "sha512-evhTyWhbwbI3/U6dZAnx/ePoV7H6OUG+OjiJFHmhr9FPn0VShjwC2kdxqIuQ/+1P50TMrneGzMeyMTFOjKSnAw==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.9.0.tgz", + "integrity": "sha512-uTWkXkIVtg/JGRSIABdBoMsoIeoHQHPTL0Y2E7xf5Oj7sLqwVsNXOkNk0VJc7vF0IMBsPeikHxFjGe+qmwPtTQ==", "requires": { - "@babel/helper-module-transforms": "^7.8.3", + "@babel/helper-module-transforms": "^7.9.0", "@babel/helper-plugin-utils": "^7.8.3" } }, @@ -874,11 +852,10 @@ } }, "@babel/plugin-transform-parameters": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.8.3.tgz", - "integrity": "sha512-/pqngtGb54JwMBZ6S/D3XYylQDFtGjWrnoCF4gXZOUpFV/ujbxnoNGNvDGu6doFWRPBveE72qTx/RRU44j5I/Q==", + "version": "7.9.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.9.3.tgz", + "integrity": "sha512-fzrQFQhp7mIhOzmOtPiKffvCYQSK10NR8t6BBz2yPbeUHb9OLW8RZGtgDRBn8z2hGcwvKDL3vC7ojPTLNxmqEg==", "requires": { - "@babel/helper-call-delegate": "^7.8.3", "@babel/helper-get-function-arity": "^7.8.3", "@babel/helper-plugin-utils": "^7.8.3" } @@ -892,37 +869,11 @@ } }, "@babel/plugin-transform-react-constant-elements": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.8.3.tgz", - "integrity": "sha512-glrzN2U+egwRfkNFtL34xIBYTxbbUF2qJTP8HD3qETBBqzAWSeNB821X0GjU06+dNpq/UyCIjI72FmGE5NNkQQ==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.9.0.tgz", + "integrity": "sha512-wXMXsToAUOxJuBBEHajqKLFWcCkOSLshTI2ChCFFj1zDd7od4IOxiwLCOObNUvOpkxLpjIuaIdBMmNt6ocCPAw==", "requires": { - "@babel/helper-annotate-as-pure": "^7.8.3", "@babel/helper-plugin-utils": "^7.8.3" - }, - "dependencies": { - "@babel/helper-annotate-as-pure": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz", - "integrity": "sha512-6o+mJrZBxOoEX77Ezv9zwW7WV8DdluouRKNY/IR5u/YTMuKHgugHOzYWlYvYLpLA9nPsQCAAASpCIbjI9Mv+Uw==", - "requires": { - "@babel/types": "^7.8.3" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", - "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==" - }, - "@babel/types": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", - "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.13", - "to-fast-properties": "^2.0.0" - } - } } }, "@babel/plugin-transform-react-display-name": { @@ -934,64 +885,50 @@ } }, "@babel/plugin-transform-react-jsx": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.8.3.tgz", - "integrity": "sha512-r0h+mUiyL595ikykci+fbwm9YzmuOrUBi0b+FDIKmi3fPQyFokWVEMJnRWHJPPQEjyFJyna9WZC6Viv6UHSv1g==", + "version": "7.9.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.9.4.tgz", + "integrity": "sha512-Mjqf3pZBNLt854CK0C/kRuXAnE6H/bo7xYojP+WGtX8glDGSibcwnsWwhwoSuRg0+EBnxPC1ouVnuetUIlPSAw==", + "requires": { + "@babel/helper-builder-react-jsx": "^7.9.0", + "@babel/helper-builder-react-jsx-experimental": "^7.9.0", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-jsx": "^7.8.3" + } + }, + "@babel/plugin-transform-react-jsx-development": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.9.0.tgz", + "integrity": "sha512-tK8hWKrQncVvrhvtOiPpKrQjfNX3DtkNLSX4ObuGcpS9p0QrGetKmlySIGR07y48Zft8WVgPakqd/bk46JrMSw==", "requires": { - "@babel/helper-builder-react-jsx": "^7.8.3", + "@babel/helper-builder-react-jsx-experimental": "^7.9.0", "@babel/helper-plugin-utils": "^7.8.3", "@babel/plugin-syntax-jsx": "^7.8.3" } }, "@babel/plugin-transform-react-jsx-self": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.8.3.tgz", - "integrity": "sha512-01OT7s5oa0XTLf2I8XGsL8+KqV9lx3EZV+jxn/L2LQ97CGKila2YMroTkCEIE0HV/FF7CMSRsIAybopdN9NTdg==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.9.0.tgz", + "integrity": "sha512-K2ObbWPKT7KUTAoyjCsFilOkEgMvFG+y0FqOl6Lezd0/13kMkkjHskVsZvblRPj1PHA44PrToaZANrryppzTvQ==", "requires": { "@babel/helper-plugin-utils": "^7.8.3", "@babel/plugin-syntax-jsx": "^7.8.3" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", - "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==" - }, - "@babel/plugin-syntax-jsx": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.8.3.tgz", - "integrity": "sha512-WxdW9xyLgBdefoo0Ynn3MRSkhe5tFVxxKNVdnZSh318WrG2e2jH+E9wd/++JsqcLJZPfz87njQJ8j2Upjm0M0A==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.3" - } - } } }, "@babel/plugin-transform-react-jsx-source": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.8.3.tgz", - "integrity": "sha512-PLMgdMGuVDtRS/SzjNEQYUT8f4z1xb2BAT54vM1X5efkVuYBf5WyGUMbpmARcfq3NaglIwz08UVQK4HHHbC6ag==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.9.0.tgz", + "integrity": "sha512-K6m3LlSnTSfRkM6FcRk8saNEeaeyG5k7AVkBU2bZK3+1zdkSED3qNdsWrUgQBeTVD2Tp3VMmerxVO2yM5iITmw==", "requires": { "@babel/helper-plugin-utils": "^7.8.3", "@babel/plugin-syntax-jsx": "^7.8.3" } }, "@babel/plugin-transform-regenerator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.3.tgz", - "integrity": "sha512-qt/kcur/FxrQrzFR432FGZznkVAjiyFtCOANjkAKwCbt465L6ZCiUQh2oMYGU3Wo8LRFJxNDFwWn106S5wVUNA==", + "version": "7.8.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.7.tgz", + "integrity": "sha512-TIg+gAl4Z0a3WmD3mbYSk+J9ZUH6n/Yc57rtKRnlA/7rcCvpekHXe0CMZHP1gYp7/KLe9GHTuIba0vXmls6drA==", "requires": { - "regenerator-transform": "^0.14.0" - }, - "dependencies": { - "regenerator-transform": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.1.tgz", - "integrity": "sha512-flVuee02C3FKRISbxhXl9mGzdbWUVHubl1SMaknjxkFB1/iqpJhArQUvRxOOPEc/9tAiX0BaQ28FJH10E4isSQ==", - "requires": { - "private": "^0.1.6" - } - } + "regenerator-transform": "^0.14.2" } }, "@babel/plugin-transform-reserved-words": { @@ -1003,9 +940,9 @@ } }, "@babel/plugin-transform-runtime": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.8.3.tgz", - "integrity": "sha512-/vqUt5Yh+cgPZXXjmaG9NT8aVfThKk7G4OqkVhrXqwsC5soMn/qTCxs36rZ2QFhpfTJcjw4SNDIZ4RUb8OL4jQ==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.9.0.tgz", + "integrity": "sha512-pUu9VSf3kI1OqbWINQ7MaugnitRss1z533436waNXp+0N3ur3zfut37sXiQMxkuCF4VUjwZucen/quskCh7NHw==", "requires": { "@babel/helper-module-imports": "^7.8.3", "@babel/helper-plugin-utils": "^7.8.3", @@ -1055,17 +992,17 @@ } }, "@babel/plugin-transform-typeof-symbol": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.3.tgz", - "integrity": "sha512-3TrkKd4LPqm4jHs6nPtSDI/SV9Cm5PRJkHLUgTcqRQQTMAZ44ZaAdDZJtvWFSaRcvT0a1rTmJ5ZA5tDKjleF3g==", + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.4.tgz", + "integrity": "sha512-2QKyfjGdvuNfHsb7qnBBlKclbD4CfshH2KvDabiijLMGXPHJXGxtDzwIF7bQP+T0ysw8fYTtxPafgfs/c1Lrqg==", "requires": { "@babel/helper-plugin-utils": "^7.8.3" } }, "@babel/plugin-transform-typescript": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.8.3.tgz", - "integrity": "sha512-Ebj230AxcrKGZPKIp4g4TdQLrqX95TobLUWKd/CwG7X1XHUH1ZpkpFvXuXqWbtGRWb7uuEWNlrl681wsOArAdQ==", + "version": "7.9.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.9.4.tgz", + "integrity": "sha512-yeWeUkKx2auDbSxRe8MusAG+n4m9BFY/v+lPjmQDgOFX5qnySkUY5oXzkp6FwPdsYqnKay6lorXYdC0n3bZO7w==", "requires": { "@babel/helper-create-class-features-plugin": "^7.8.3", "@babel/helper-plugin-utils": "^7.8.3", @@ -1082,26 +1019,28 @@ } }, "@babel/preset-env": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.8.3.tgz", - "integrity": "sha512-Rs4RPL2KjSLSE2mWAx5/iCH+GC1ikKdxPrhnRS6PfFVaiZeom22VFKN4X8ZthyN61kAaR05tfXTbCvatl9WIQg==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.9.0.tgz", + "integrity": "sha512-712DeRXT6dyKAM/FMbQTV/FvRCms2hPCx+3weRjZ8iQVQWZejWWk1wwG6ViWMyqb/ouBbGOl5b6aCk0+j1NmsQ==", "requires": { - "@babel/compat-data": "^7.8.0", - "@babel/helper-compilation-targets": "^7.8.3", + "@babel/compat-data": "^7.9.0", + "@babel/helper-compilation-targets": "^7.8.7", "@babel/helper-module-imports": "^7.8.3", "@babel/helper-plugin-utils": "^7.8.3", "@babel/plugin-proposal-async-generator-functions": "^7.8.3", "@babel/plugin-proposal-dynamic-import": "^7.8.3", "@babel/plugin-proposal-json-strings": "^7.8.3", "@babel/plugin-proposal-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-proposal-object-rest-spread": "^7.8.3", + "@babel/plugin-proposal-numeric-separator": "^7.8.3", + "@babel/plugin-proposal-object-rest-spread": "^7.9.0", "@babel/plugin-proposal-optional-catch-binding": "^7.8.3", - "@babel/plugin-proposal-optional-chaining": "^7.8.3", + "@babel/plugin-proposal-optional-chaining": "^7.9.0", "@babel/plugin-proposal-unicode-property-regex": "^7.8.3", "@babel/plugin-syntax-async-generators": "^7.8.0", "@babel/plugin-syntax-dynamic-import": "^7.8.0", "@babel/plugin-syntax-json-strings": "^7.8.0", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0", + "@babel/plugin-syntax-numeric-separator": "^7.8.0", "@babel/plugin-syntax-object-rest-spread": "^7.8.0", "@babel/plugin-syntax-optional-catch-binding": "^7.8.0", "@babel/plugin-syntax-optional-chaining": "^7.8.0", @@ -1110,90 +1049,53 @@ "@babel/plugin-transform-async-to-generator": "^7.8.3", "@babel/plugin-transform-block-scoped-functions": "^7.8.3", "@babel/plugin-transform-block-scoping": "^7.8.3", - "@babel/plugin-transform-classes": "^7.8.3", + "@babel/plugin-transform-classes": "^7.9.0", "@babel/plugin-transform-computed-properties": "^7.8.3", "@babel/plugin-transform-destructuring": "^7.8.3", "@babel/plugin-transform-dotall-regex": "^7.8.3", "@babel/plugin-transform-duplicate-keys": "^7.8.3", "@babel/plugin-transform-exponentiation-operator": "^7.8.3", - "@babel/plugin-transform-for-of": "^7.8.3", + "@babel/plugin-transform-for-of": "^7.9.0", "@babel/plugin-transform-function-name": "^7.8.3", "@babel/plugin-transform-literals": "^7.8.3", "@babel/plugin-transform-member-expression-literals": "^7.8.3", - "@babel/plugin-transform-modules-amd": "^7.8.3", - "@babel/plugin-transform-modules-commonjs": "^7.8.3", - "@babel/plugin-transform-modules-systemjs": "^7.8.3", - "@babel/plugin-transform-modules-umd": "^7.8.3", + "@babel/plugin-transform-modules-amd": "^7.9.0", + "@babel/plugin-transform-modules-commonjs": "^7.9.0", + "@babel/plugin-transform-modules-systemjs": "^7.9.0", + "@babel/plugin-transform-modules-umd": "^7.9.0", "@babel/plugin-transform-named-capturing-groups-regex": "^7.8.3", "@babel/plugin-transform-new-target": "^7.8.3", "@babel/plugin-transform-object-super": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.8.7", "@babel/plugin-transform-property-literals": "^7.8.3", - "@babel/plugin-transform-regenerator": "^7.8.3", + "@babel/plugin-transform-regenerator": "^7.8.7", "@babel/plugin-transform-reserved-words": "^7.8.3", "@babel/plugin-transform-shorthand-properties": "^7.8.3", "@babel/plugin-transform-spread": "^7.8.3", "@babel/plugin-transform-sticky-regex": "^7.8.3", "@babel/plugin-transform-template-literals": "^7.8.3", - "@babel/plugin-transform-typeof-symbol": "^7.8.3", + "@babel/plugin-transform-typeof-symbol": "^7.8.4", "@babel/plugin-transform-unicode-regex": "^7.8.3", - "@babel/types": "^7.8.3", - "browserslist": "^4.8.2", + "@babel/preset-modules": "^0.1.3", + "@babel/types": "^7.9.0", + "browserslist": "^4.9.1", "core-js-compat": "^3.6.2", "invariant": "^2.2.2", - "levenary": "^1.1.0", + "levenary": "^1.1.1", "semver": "^5.5.0" }, "dependencies": { - "browserslist": { - "version": "4.8.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.5.tgz", - "integrity": "sha512-4LMHuicxkabIB+n9874jZX/az1IaZ5a+EUuvD7KFOu9x/Bd5YHyO0DIz2ls/Kl8g0ItS4X/ilEgf4T1Br0lgSg==", - "requires": { - "caniuse-lite": "^1.0.30001022", - "electron-to-chromium": "^1.3.338", - "node-releases": "^1.1.46" - } - }, - "caniuse-lite": { - "version": "1.0.30001022", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001022.tgz", - "integrity": "sha512-FjwPPtt/I07KyLPkBQ0g7/XuZg6oUkYBVnPHNj3VHJbOjmmJ/GdSo/GUY6MwINEQvjhP6WZVbX8Tvms8xh0D5A==" - }, - "core-js-compat": { - "version": "3.6.4", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.6.4.tgz", - "integrity": "sha512-zAa3IZPvsJ0slViBQ2z+vgyyTuhd3MFn1rBQjZSKVEgB0UMYhUkCj9jJUVPgGTGqWvsBVmfnruXgTcNyTlEiSA==", - "requires": { - "browserslist": "^4.8.3", - "semver": "7.0.0" - }, - "dependencies": { - "semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==" - } - } - }, - "electron-to-chromium": { - "version": "1.3.340", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.340.tgz", - "integrity": "sha512-hRFBAglhcj5iVYH+o8QU0+XId1WGoc0VGowJB1cuJAt3exHGrivZvWeAO5BRgBZqwZtwxjm8a5MQeGoT/Su3ww==" + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" }, - "node-releases": { - "version": "1.1.47", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.47.tgz", - "integrity": "sha512-k4xjVPx5FpwBUj0Gw7uvFOTF4Ep8Hok1I6qjwL3pLfwe7Y0REQSAqOwwv9TWBCUtMHxcXfY4PgRLRozcChvTcA==", + "levenary": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/levenary/-/levenary-1.1.1.tgz", + "integrity": "sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ==", "requires": { - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } + "leven": "^3.1.0" } }, "semver": { @@ -1204,328 +1106,54 @@ } }, "@babel/preset-flow": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.8.3.tgz", - "integrity": "sha512-iCXFk+T4demnq+dNLLvlGOgvYF6sPZ/hS1EmswugOqh1Ysp2vuiqJzpgsnp5rW8+6dLJT/0CXDzye28ZH6BAfQ==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.9.0.tgz", + "integrity": "sha512-88uSmlshIrlmPkNkEcx3UpSZ6b8n0UGBq0/0ZMZCF/uxAW0XIAUuDHBhIOAh0pvweafH4RxOwi/H3rWhtqOYPA==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.8.3", - "@babel/plugin-transform-flow-strip-types": "^7.8.3" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", - "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", - "dev": true - }, - "@babel/plugin-syntax-flow": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.8.3.tgz", - "integrity": "sha512-innAx3bUbA0KSYj2E2MNFSn9hiCeowOFLxlsuhXzw8hMQnzkDomUr9QCD7E9VF60NmnG1sNTuuv6Qf4f8INYsg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.3" - } - }, - "@babel/plugin-transform-flow-strip-types": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.8.3.tgz", - "integrity": "sha512-g/6WTWG/xbdd2exBBzMfygjX/zw4eyNC4X8pRaq7aRHRoDUCzAIu3kGYIXviOv8BjCuWm8vDBwjHcjiRNgXrPA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.3", - "@babel/plugin-syntax-flow": "^7.8.3" - } - } + "@babel/plugin-transform-flow-strip-types": "^7.9.0" + } + }, + "@babel/preset-modules": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.3.tgz", + "integrity": "sha512-Ra3JXOHBq2xd56xSF7lMKXdjBn3T772Y1Wet3yWnkDly9zHvJki029tAFzvAAK5cf4YV3yoxuP61crYRol6SVg==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" } }, "@babel/preset-react": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.8.3.tgz", - "integrity": "sha512-9hx0CwZg92jGb7iHYQVgi0tOEHP/kM60CtWJQnmbATSPIQQ2xYzfoCI3EdqAhFBeeJwYMdWQuDUHMsuDbH9hyQ==", + "version": "7.9.4", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.9.4.tgz", + "integrity": "sha512-AxylVB3FXeOTQXNXyiuAQJSvss62FEotbX2Pzx3K/7c+MKJMdSg6Ose6QYllkdCFA8EInCJVw7M/o5QbLuA4ZQ==", "requires": { "@babel/helper-plugin-utils": "^7.8.3", "@babel/plugin-transform-react-display-name": "^7.8.3", - "@babel/plugin-transform-react-jsx": "^7.8.3", - "@babel/plugin-transform-react-jsx-self": "^7.8.3", - "@babel/plugin-transform-react-jsx-source": "^7.8.3" - }, - "dependencies": { - "@babel/helper-builder-react-jsx": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.8.3.tgz", - "integrity": "sha512-JT8mfnpTkKNCboTqZsQTdGo3l3Ik3l7QIt9hh0O9DYiwVel37VoJpILKM4YFbP2euF32nkQSb+F9cUk9b7DDXQ==", - "requires": { - "@babel/types": "^7.8.3", - "esutils": "^2.0.0" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", - "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==" - }, - "@babel/plugin-syntax-jsx": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.8.3.tgz", - "integrity": "sha512-WxdW9xyLgBdefoo0Ynn3MRSkhe5tFVxxKNVdnZSh318WrG2e2jH+E9wd/++JsqcLJZPfz87njQJ8j2Upjm0M0A==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.3" - } - }, - "@babel/plugin-transform-react-display-name": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.8.3.tgz", - "integrity": "sha512-3Jy/PCw8Fe6uBKtEgz3M82ljt+lTg+xJaM4og+eyu83qLT87ZUSckn0wy7r31jflURWLO83TW6Ylf7lyXj3m5A==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.3" - } - }, - "@babel/plugin-transform-react-jsx": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.8.3.tgz", - "integrity": "sha512-r0h+mUiyL595ikykci+fbwm9YzmuOrUBi0b+FDIKmi3fPQyFokWVEMJnRWHJPPQEjyFJyna9WZC6Viv6UHSv1g==", - "requires": { - "@babel/helper-builder-react-jsx": "^7.8.3", - "@babel/helper-plugin-utils": "^7.8.3", - "@babel/plugin-syntax-jsx": "^7.8.3" - } - }, - "@babel/plugin-transform-react-jsx-source": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.8.3.tgz", - "integrity": "sha512-PLMgdMGuVDtRS/SzjNEQYUT8f4z1xb2BAT54vM1X5efkVuYBf5WyGUMbpmARcfq3NaglIwz08UVQK4HHHbC6ag==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.3", - "@babel/plugin-syntax-jsx": "^7.8.3" - } - }, - "@babel/types": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", - "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.13", - "to-fast-properties": "^2.0.0" - } - } + "@babel/plugin-transform-react-jsx": "^7.9.4", + "@babel/plugin-transform-react-jsx-development": "^7.9.0", + "@babel/plugin-transform-react-jsx-self": "^7.9.0", + "@babel/plugin-transform-react-jsx-source": "^7.9.0" } }, "@babel/preset-typescript": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.8.3.tgz", - "integrity": "sha512-qee5LgPGui9zQ0jR1TeU5/fP9L+ovoArklEqY12ek8P/wV5ZeM/VYSQYwICeoT6FfpJTekG9Ilay5PhwsOpMHA==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.9.0.tgz", + "integrity": "sha512-S4cueFnGrIbvYJgwsVFKdvOmpiL0XGw9MFW9D0vgRys5g36PBhZRL8NX8Gr2akz8XRtzq6HuDXPD/1nniagNUg==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.8.3", - "@babel/plugin-transform-typescript": "^7.8.3" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", - "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.8.3" - } - }, - "@babel/generator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.3.tgz", - "integrity": "sha512-WjoPk8hRpDRqqzRpvaR8/gDUPkrnOOeuT2m8cNICJtZH6mwaCo3v0OKMI7Y6SM1pBtyijnLtAL0HDi41pf41ug==", - "dev": true, - "requires": { - "@babel/types": "^7.8.3", - "jsesc": "^2.5.1", - "lodash": "^4.17.13", - "source-map": "^0.5.0" - } - }, - "@babel/helper-create-class-features-plugin": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.8.3.tgz", - "integrity": "sha512-qmp4pD7zeTxsv0JNecSBsEmG1ei2MqwJq4YQcK3ZWm/0t07QstWfvuV/vm3Qt5xNMFETn2SZqpMx2MQzbtq+KA==", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.8.3", - "@babel/helper-member-expression-to-functions": "^7.8.3", - "@babel/helper-optimise-call-expression": "^7.8.3", - "@babel/helper-plugin-utils": "^7.8.3", - "@babel/helper-replace-supers": "^7.8.3", - "@babel/helper-split-export-declaration": "^7.8.3" - } - }, - "@babel/helper-function-name": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz", - "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.8.3", - "@babel/template": "^7.8.3", - "@babel/types": "^7.8.3" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", - "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", - "dev": true, - "requires": { - "@babel/types": "^7.8.3" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz", - "integrity": "sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA==", - "dev": true, - "requires": { - "@babel/types": "^7.8.3" - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz", - "integrity": "sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ==", - "dev": true, - "requires": { - "@babel/types": "^7.8.3" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", - "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", - "dev": true - }, - "@babel/helper-replace-supers": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.8.3.tgz", - "integrity": "sha512-xOUssL6ho41U81etpLoT2RTdvdus4VfHamCuAm4AHxGr+0it5fnwoVdwUJ7GFEqCsQYzJUhcbsN9wB9apcYKFA==", - "dev": true, - "requires": { - "@babel/helper-member-expression-to-functions": "^7.8.3", - "@babel/helper-optimise-call-expression": "^7.8.3", - "@babel/traverse": "^7.8.3", - "@babel/types": "^7.8.3" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", - "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", - "dev": true, - "requires": { - "@babel/types": "^7.8.3" - } - }, - "@babel/highlight": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", - "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", - "dev": true, - "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.3.tgz", - "integrity": "sha512-/V72F4Yp/qmHaTALizEm9Gf2eQHV3QyTL3K0cNfijwnMnb1L+LDlAubb/ZnSdGAVzVSWakujHYs1I26x66sMeQ==", - "dev": true - }, - "@babel/plugin-syntax-typescript": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.8.3.tgz", - "integrity": "sha512-GO1MQ/SGGGoiEXY0e0bSpHimJvxqB7lktLLIq2pv8xG7WZ8IMEle74jIe1FhprHBWjwjZtXHkycDLZXIWM5Wfg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.3" - } - }, - "@babel/plugin-transform-typescript": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.8.3.tgz", - "integrity": "sha512-Ebj230AxcrKGZPKIp4g4TdQLrqX95TobLUWKd/CwG7X1XHUH1ZpkpFvXuXqWbtGRWb7uuEWNlrl681wsOArAdQ==", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.8.3", - "@babel/helper-plugin-utils": "^7.8.3", - "@babel/plugin-syntax-typescript": "^7.8.3" - } - }, - "@babel/template": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", - "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.8.3", - "@babel/parser": "^7.8.3", - "@babel/types": "^7.8.3" - } - }, - "@babel/traverse": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.3.tgz", - "integrity": "sha512-we+a2lti+eEImHmEXp7bM9cTxGzxPmBiVJlLVD+FuuQMeeO7RaDbutbgeheDkw+Xe3mCfJHnGOWLswT74m2IPg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.8.3", - "@babel/generator": "^7.8.3", - "@babel/helper-function-name": "^7.8.3", - "@babel/helper-split-export-declaration": "^7.8.3", - "@babel/parser": "^7.8.3", - "@babel/types": "^7.8.3", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.13" - } - }, - "@babel/types": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", - "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", - "dev": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.13", - "to-fast-properties": "^2.0.0" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } + "@babel/plugin-transform-typescript": "^7.9.0" } }, "@babel/register": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.8.3.tgz", - "integrity": "sha512-t7UqebaWwo9nXWClIPLPloa5pN33A2leVs8Hf0e9g9YwUP8/H9NeR7DJU+4CXo23QtjChQv5a3DjEtT83ih1rg==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.9.0.tgz", + "integrity": "sha512-Tv8Zyi2J2VRR8g7pC5gTeIN8Ihultbmk0ocyNz8H2nEZbmhp1N6q0A1UGsQbDvGP/sNinQKUHf3SqXwqjtFv4Q==", "requires": { "find-cache-dir": "^2.0.0", "lodash": "^4.17.13", @@ -1571,9 +1199,9 @@ } }, "p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "requires": { "p-try": "^2.0.0" } @@ -1626,44 +1254,57 @@ } }, "@babel/runtime": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.8.3.tgz", - "integrity": "sha512-fVHx1rzEmwB130VTkLnxR+HmxcTjGzH12LYQcFFoBwakMd3aOMD4OsRN7tGG/UOYE2ektgFrS8uACAoRk1CY0w==", + "version": "7.9.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.2.tgz", + "integrity": "sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q==", "requires": { - "regenerator-runtime": "^0.13.2" + "regenerator-runtime": "^0.13.4" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.13.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz", + "integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==" + } } }, "@babel/runtime-corejs3": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.8.3.tgz", - "integrity": "sha512-lrIU4aVbmlM/wQPzhEvzvNJskKyYptuXb0fGC0lTQTupTOYtR2Vqbu6/jf8vTr4M8Wt1nIzxVrSvPI5qESa/xA==", - "dev": true, + "version": "7.9.2", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.9.2.tgz", + "integrity": "sha512-HHxmgxbIzOfFlZ+tdeRKtaxWOMUoCG5Mu3wKeUmOxjYrwb3AAHgnmtCUbPPK11/raIWLIBK250t8E2BPO0p7jA==", "requires": { "core-js-pure": "^3.0.0", - "regenerator-runtime": "^0.13.2" - } + "regenerator-runtime": "^0.13.4" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.13.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz", + "integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==" + } + } }, "@babel/template": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", - "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", + "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==", "requires": { "@babel/code-frame": "^7.8.3", - "@babel/parser": "^7.8.3", - "@babel/types": "^7.8.3" + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6" } }, "@babel/traverse": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.3.tgz", - "integrity": "sha512-we+a2lti+eEImHmEXp7bM9cTxGzxPmBiVJlLVD+FuuQMeeO7RaDbutbgeheDkw+Xe3mCfJHnGOWLswT74m2IPg==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.9.0.tgz", + "integrity": "sha512-jAZQj0+kn4WTHO5dUZkZKhbFrqZE7K5LAQ5JysMnmvGij+wOdr+8lWqPeW0BcF4wFwrEXXtdGO7wcV6YPJcf3w==", "requires": { "@babel/code-frame": "^7.8.3", - "@babel/generator": "^7.8.3", + "@babel/generator": "^7.9.0", "@babel/helper-function-name": "^7.8.3", "@babel/helper-split-export-declaration": "^7.8.3", - "@babel/parser": "^7.8.3", - "@babel/types": "^7.8.3", + "@babel/parser": "^7.9.0", + "@babel/types": "^7.9.0", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.13" @@ -1690,11 +1331,11 @@ } }, "@babel/types": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", - "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.0.tgz", + "integrity": "sha512-BS9JKfXkzzJl8RluW4JGknzpiUV7ZrvTayM6yfqLTVBEnFtyowVIOu6rqxRd5cVO6yGoWf4T8u8dgK9oB+GCng==", "requires": { - "esutils": "^2.0.2", + "@babel/helper-validator-identifier": "^7.9.0", "lodash": "^4.17.13", "to-fast-properties": "^2.0.0" } @@ -1705,6 +1346,11 @@ "integrity": "sha512-4Th98KlMHr5+JkxfcoDT//6vY8vM+iSPrLNpHhRyLx2CFYi8e2RfqPLdpbnpo0Q5lQC5hNB79yes07zb02fvCw==", "dev": true }, + "@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==" + }, "@cnakazawa/watch": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.3.tgz", @@ -1724,6 +1370,7 @@ "version": "10.0.19", "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-10.0.19.tgz", "integrity": "sha512-BoiLlk4vEsGBg2dAqGSJu0vJl/PgVtCYLBFJaEO8RmQzPugXewQCXZJNXTDFaRlfCs0W+quesayav4fvaif5WQ==", + "dev": true, "requires": { "@emotion/sheet": "0.9.3", "@emotion/stylis": "0.8.4", @@ -1732,47 +1379,48 @@ } }, "@emotion/core": { - "version": "10.0.22", - "resolved": "https://registry.npmjs.org/@emotion/core/-/core-10.0.22.tgz", - "integrity": "sha512-7eoP6KQVUyOjAkE6y4fdlxbZRA4ILs7dqkkm6oZUJmihtHv0UBq98VgPirq9T8F9K2gKu0J/au/TpKryKMinaA==", + "version": "10.0.28", + "resolved": "https://registry.npmjs.org/@emotion/core/-/core-10.0.28.tgz", + "integrity": "sha512-pH8UueKYO5jgg0Iq+AmCLxBsvuGtvlmiDCOuv8fGNYn3cowFpLN98L8zO56U0H1PjDIyAlXymgL3Wu7u7v6hbA==", "requires": { "@babel/runtime": "^7.5.5", - "@emotion/cache": "^10.0.17", - "@emotion/css": "^10.0.22", - "@emotion/serialize": "^0.11.12", - "@emotion/sheet": "0.9.3", - "@emotion/utils": "0.11.2" + "@emotion/cache": "^10.0.27", + "@emotion/css": "^10.0.27", + "@emotion/serialize": "^0.11.15", + "@emotion/sheet": "0.9.4", + "@emotion/utils": "0.11.3" }, "dependencies": { - "@babel/runtime": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.7.2.tgz", - "integrity": "sha512-JONRbXbTXc9WQE2mAZd1p0Z3DZ/6vaQIkgYMSTP3KjRCyd7rCZCcfhCyX+YjwcKxcZ82UrxbRD358bpExNgrjw==", + "@emotion/cache": { + "version": "10.0.29", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-10.0.29.tgz", + "integrity": "sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ==", "requires": { - "regenerator-runtime": "^0.13.2" + "@emotion/sheet": "0.9.4", + "@emotion/stylis": "0.8.5", + "@emotion/utils": "0.11.3", + "@emotion/weak-memoize": "0.2.5" } }, - "@emotion/css": { - "version": "10.0.22", - "resolved": "https://registry.npmjs.org/@emotion/css/-/css-10.0.22.tgz", - "integrity": "sha512-8phfa5mC/OadBTmGpMpwykIVH0gFCbUoO684LUkyixPq4F1Wwri7fK5Xlm8lURNBrd2TuvTbPUGxFsGxF9UacA==", - "requires": { - "@emotion/serialize": "^0.11.12", - "@emotion/utils": "0.11.2", - "babel-plugin-emotion": "^10.0.22" - } + "@emotion/sheet": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-0.9.4.tgz", + "integrity": "sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA==" }, - "@emotion/serialize": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.14.tgz", - "integrity": "sha512-6hTsySIuQTbDbv00AnUO6O6Xafdwo5GswRlMZ5hHqiFx+4pZ7uGWXUQFW46Kc2taGhP89uXMXn/lWQkdyTosPA==", - "requires": { - "@emotion/hash": "0.7.3", - "@emotion/memoize": "0.7.3", - "@emotion/unitless": "0.7.4", - "@emotion/utils": "0.11.2", - "csstype": "^2.5.7" - } + "@emotion/stylis": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz", + "integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==" + }, + "@emotion/utils": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.11.3.tgz", + "integrity": "sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==" + }, + "@emotion/weak-memoize": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz", + "integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==" } } }, @@ -1891,7 +1539,8 @@ "@emotion/sheet": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-0.9.3.tgz", - "integrity": "sha512-c3Q6V7Df7jfwSq5AzQWbXHa5soeE4F5cbqi40xn0CzXxWW9/6Mxq48WJEtqfWzbZtW9odZdnRAkwCQwN12ob4A==" + "integrity": "sha512-c3Q6V7Df7jfwSq5AzQWbXHa5soeE4F5cbqi40xn0CzXxWW9/6Mxq48WJEtqfWzbZtW9odZdnRAkwCQwN12ob4A==", + "dev": true }, "@emotion/styled": { "version": "10.0.23", @@ -1938,7 +1587,8 @@ "@emotion/stylis": { "version": "0.8.4", "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.4.tgz", - "integrity": "sha512-TLmkCVm8f8gH0oLv+HWKiu7e8xmBIaokhxcEKPh1m8pXiV/akCiq50FvYgOwY42rjejck8nsdQxZlXZ7pmyBUQ==" + "integrity": "sha512-TLmkCVm8f8gH0oLv+HWKiu7e8xmBIaokhxcEKPh1m8pXiV/akCiq50FvYgOwY42rjejck8nsdQxZlXZ7pmyBUQ==", + "dev": true }, "@emotion/unitless": { "version": "0.7.4", @@ -1953,7 +1603,8 @@ "@emotion/weak-memoize": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.4.tgz", - "integrity": "sha512-6PYY5DVdAY1ifaQW6XYTnOMihmBVT27elqSjEoodchsGjzYlEsTQMcEhSud99kVawatyTZRTiVkJ/c6lwbQ7nA==" + "integrity": "sha512-6PYY5DVdAY1ifaQW6XYTnOMihmBVT27elqSjEoodchsGjzYlEsTQMcEhSud99kVawatyTZRTiVkJ/c6lwbQ7nA==", + "dev": true }, "@evocateur/libnpmaccess": { "version": "3.1.2", @@ -2378,16 +2029,97 @@ "integrity": "sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==", "dev": true }, + "@istanbuljs/load-nyc-config": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.0.0.tgz", + "integrity": "sha512-ZR0rq/f/E4f4XcgnDvtMWXCUJpi8eO0rssVhmztsZqLIEFA9UUP9zmpE0VxlM+kv/E1ul2I876Fwil2ayptDVg==", + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" + } + } + }, + "@istanbuljs/schema": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", + "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==" + }, "@jest/console": { - "version": "24.7.1", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.7.1.tgz", - "integrity": "sha512-iNhtIy2M8bXlAOULWVTUxmnelTLFneTNEkHCgPmgd+zNwy9zVddJ6oS5rZ9iwoscNdT5mMwUd0C51v/fSlzItg==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", + "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", "requires": { - "@jest/source-map": "^24.3.0", + "@jest/source-map": "^24.9.0", "chalk": "^2.0.1", "slash": "^2.0.0" }, "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, "slash": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", @@ -2399,6 +2131,7 @@ "version": "24.9.0", "resolved": "https://registry.npmjs.org/@jest/core/-/core-24.9.0.tgz", "integrity": "sha512-Fogg3s4wlAr1VX7q+rhV9RVnUv5tD7VuWfYy1+whMiWUrvl7U3QJSJyWcDio9Lq2prqYsZaeTv2Rz24pWGkJ2A==", + "dev": true, "requires": { "@jest/console": "^24.7.1", "@jest/reporters": "^24.9.0", @@ -2430,52 +2163,40 @@ "strip-ansi": "^5.0.0" }, "dependencies": { - "@jest/fake-timers": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz", - "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", - "requires": { - "@jest/types": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-mock": "^24.9.0" - } - }, - "@jest/source-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", - "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.1.15", - "source-map": "^0.6.0" - } - }, - "@jest/test-result": { + "@jest/reporters": { "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", - "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-24.9.0.tgz", + "integrity": "sha512-mu4X0yjaHrffOsWmVLzitKmmmWSQ3GGuefgNscUSWNiUNcEOSEQk9k3pERKEQVBb0Cnn88+UESIsZEMH3o88Gw==", + "dev": true, "requires": { - "@jest/console": "^24.9.0", + "@jest/environment": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/transform": "^24.9.0", "@jest/types": "^24.9.0", - "@types/istanbul-lib-coverage": "^2.0.0" - }, - "dependencies": { - "@jest/console": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", - "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", - "requires": { - "@jest/source-map": "^24.9.0", - "chalk": "^2.0.1", - "slash": "^2.0.0" - } - } + "chalk": "^2.0.1", + "exit": "^0.1.2", + "glob": "^7.1.2", + "istanbul-lib-coverage": "^2.0.2", + "istanbul-lib-instrument": "^3.0.1", + "istanbul-lib-report": "^2.0.4", + "istanbul-lib-source-maps": "^3.0.1", + "istanbul-reports": "^2.2.6", + "jest-haste-map": "^24.9.0", + "jest-resolve": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-util": "^24.9.0", + "jest-worker": "^24.6.0", + "node-notifier": "^5.4.2", + "slash": "^2.0.0", + "source-map": "^0.6.0", + "string-length": "^2.0.0" } }, "@jest/types": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^1.1.1", @@ -2483,286 +2204,220 @@ } }, "@types/yargs": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.5.tgz", - "integrity": "sha512-CF/+sxTO7FOwbIRL4wMv0ZYLCRfMid2HQpzDRyViH7kSpfoAFiMdGqKIxb1PxWfjtQXQhnQuD33lvRHNwr809Q==", + "version": "13.0.8", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz", + "integrity": "sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA==", + "dev": true, "requires": { "@types/yargs-parser": "*" } }, - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" - }, - "diff-sequences": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz", - "integrity": "sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==" + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } }, - "expect": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-24.9.0.tgz", - "integrity": "sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q==", + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, "requires": { - "@jest/types": "^24.9.0", - "ansi-styles": "^3.2.0", - "jest-get-type": "^24.9.0", - "jest-matcher-utils": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-regex-util": "^24.9.0" - }, - "dependencies": { - "jest-regex-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz", - "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==" - } + "ms": "^2.1.1" } }, "graceful-fs": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", + "dev": true }, - "jest-config": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.9.0.tgz", - "integrity": "sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ==", - "requires": { - "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^24.9.0", - "@jest/types": "^24.9.0", - "babel-jest": "^24.9.0", - "chalk": "^2.0.1", - "glob": "^7.1.1", - "jest-environment-jsdom": "^24.9.0", - "jest-environment-node": "^24.9.0", - "jest-get-type": "^24.9.0", - "jest-jasmine2": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-resolve": "^24.9.0", - "jest-util": "^24.9.0", - "jest-validate": "^24.9.0", - "micromatch": "^3.1.10", - "pretty-format": "^24.9.0", - "realpath-native": "^1.1.0" - } + "istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true }, - "jest-diff": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.9.0.tgz", - "integrity": "sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==", + "istanbul-lib-instrument": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", + "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", + "dev": true, "requires": { - "chalk": "^2.0.1", - "diff-sequences": "^24.9.0", - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" + "@babel/generator": "^7.4.0", + "@babel/parser": "^7.4.3", + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.3", + "@babel/types": "^7.4.0", + "istanbul-lib-coverage": "^2.0.5", + "semver": "^6.0.0" } }, - "jest-get-type": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", - "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==" - }, - "jest-haste-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.9.0.tgz", - "integrity": "sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ==", + "istanbul-lib-report": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", + "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", + "dev": true, "requires": { - "@jest/types": "^24.9.0", - "anymatch": "^2.0.0", - "fb-watchman": "^2.0.0", - "fsevents": "^1.2.7", - "graceful-fs": "^4.1.15", - "invariant": "^2.2.4", - "jest-serializer": "^24.9.0", - "jest-util": "^24.9.0", - "jest-worker": "^24.9.0", - "micromatch": "^3.1.10", - "sane": "^4.0.3", - "walker": "^1.0.7" + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "supports-color": "^6.1.0" + }, + "dependencies": { + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, - "jest-matcher-utils": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz", - "integrity": "sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA==", + "istanbul-lib-source-maps": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", + "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", + "dev": true, "requires": { - "chalk": "^2.0.1", - "jest-diff": "^24.9.0", - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" + "debug": "^4.1.1", + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "rimraf": "^2.6.3", + "source-map": "^0.6.1" } }, - "jest-message-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", - "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/stack-utils": "^1.0.1", - "chalk": "^2.0.1", - "micromatch": "^3.1.10", - "slash": "^2.0.0", - "stack-utils": "^1.0.1" + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } } }, - "jest-mock": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz", - "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", - "requires": { - "@jest/types": "^24.9.0" - } + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true }, - "jest-resolve": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.9.0.tgz", - "integrity": "sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ==", + "node-notifier": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.3.tgz", + "integrity": "sha512-M4UBGcs4jeOK9CjTsYwkvH6/MzuUmGCyTW+kCY7uO+1ZVr0+FHGdPdIf5CCLqAaxnRrWidyoQlNkMIIVwbKB8Q==", + "dev": true, "requires": { - "@jest/types": "^24.9.0", - "browser-resolve": "^1.11.3", - "chalk": "^2.0.1", - "jest-pnp-resolver": "^1.2.1", - "realpath-native": "^1.1.0" + "growly": "^1.3.0", + "is-wsl": "^1.1.0", + "semver": "^5.5.0", + "shellwords": "^0.1.1", + "which": "^1.3.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } } }, - "jest-serializer": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.9.0.tgz", - "integrity": "sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ==" - }, - "jest-snapshot": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-24.9.0.tgz", - "integrity": "sha512-uI/rszGSs73xCM0l+up7O7a40o90cnrk429LOiK3aeTvfC0HHmldbd81/B7Ix81KSFe1lwkbl7GnBGG4UfuDew==", - "requires": { - "@babel/types": "^7.0.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "expect": "^24.9.0", - "jest-diff": "^24.9.0", - "jest-get-type": "^24.9.0", - "jest-matcher-utils": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-resolve": "^24.9.0", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "pretty-format": "^24.9.0", - "semver": "^6.2.0" - } + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true }, - "jest-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz", - "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, "requires": { - "@jest/console": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/source-map": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "callsites": "^3.0.0", - "chalk": "^2.0.1", - "graceful-fs": "^4.1.15", - "is-ci": "^2.0.0", - "mkdirp": "^0.5.1", - "slash": "^2.0.0", - "source-map": "^0.6.0" + "glob": "^7.1.3" }, "dependencies": { - "@jest/console": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", - "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, "requires": { - "@jest/source-map": "^24.9.0", - "chalk": "^2.0.1", - "slash": "^2.0.0" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } } } }, - "jest-validate": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.9.0.tgz", - "integrity": "sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ==", - "requires": { - "@jest/types": "^24.9.0", - "camelcase": "^5.3.1", - "chalk": "^2.0.1", - "jest-get-type": "^24.9.0", - "leven": "^3.1.0", - "pretty-format": "^24.9.0" - } - }, - "jest-worker": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", - "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", - "requires": { - "merge-stream": "^2.0.0", - "supports-color": "^6.1.0" - } - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" - }, - "pretty-format": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", - "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", - "requires": { - "@jest/types": "^24.9.0", - "ansi-regex": "^4.0.0", - "ansi-styles": "^3.2.0", - "react-is": "^16.8.4" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - }, "slash": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==" + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "string-length": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", + "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", + "dev": true, + "requires": { + "astral-regex": "^1.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, "requires": { "ansi-regex": "^4.1.0" - } - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + } } } } @@ -2771,6 +2426,7 @@ "version": "24.9.0", "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-24.9.0.tgz", "integrity": "sha512-5A1QluTPhvdIPFYnO3sZC3smkNeXPVELz7ikPbhUj0bQjB07EoE9qtLrem14ZUYWdVayYbsjVwIiL4WBIMV4aQ==", + "dev": true, "requires": { "@jest/fake-timers": "^24.9.0", "@jest/transform": "^24.9.0", @@ -2778,46 +2434,38 @@ "jest-mock": "^24.9.0" }, "dependencies": { - "@jest/console": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", - "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", - "requires": { - "@jest/source-map": "^24.9.0", - "chalk": "^2.0.1", - "slash": "^2.0.0" - } - }, - "@jest/fake-timers": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz", - "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", - "requires": { - "@jest/types": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-mock": "^24.9.0" - } - }, - "@jest/source-map": { + "@jest/types": { "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", - "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.1.15", - "source-map": "^0.6.0" + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" } }, - "@jest/test-result": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", - "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", + "@types/yargs": { + "version": "13.0.8", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz", + "integrity": "sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA==", + "dev": true, "requires": { - "@jest/console": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/istanbul-lib-coverage": "^2.0.0" + "@types/yargs-parser": "*" } - }, + } + } + }, + "@jest/fake-timers": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz", + "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", + "requires": { + "@jest/types": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-mock": "^24.9.0" + }, + "dependencies": { "@jest/types": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", @@ -2829,249 +2477,265 @@ } }, "@types/yargs": { - "version": "13.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.4.tgz", - "integrity": "sha512-Ke1WmBbIkVM8bpvsNEcGgQM70XcEh/nbpxQhW7FhrsbCsXSY9BmLB1+LHtD7r9zrsOcFlLiF+a/UeJsdfw3C5A==", + "version": "13.0.8", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz", + "integrity": "sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA==", "requires": { "@types/yargs-parser": "*" } + } + } + }, + "@jest/reporters": { + "version": "25.3.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-25.3.0.tgz", + "integrity": "sha512-1u0ZBygs0C9DhdYgLCrRfZfNKQa+9+J7Uo+Z9z0RWLHzgsxhoG32lrmMOtUw48yR6bLNELdvzormwUqSk4H4Vg==", + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^25.3.0", + "@jest/test-result": "^25.3.0", + "@jest/transform": "^25.3.0", + "@jest/types": "^25.3.0", + "chalk": "^3.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^4.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "jest-haste-map": "^25.3.0", + "jest-resolve": "^25.3.0", + "jest-util": "^25.3.0", + "jest-worker": "^25.2.6", + "node-notifier": "^6.0.0", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^3.1.0", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^4.0.1" + }, + "dependencies": { + "@jest/console": { + "version": "25.3.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-25.3.0.tgz", + "integrity": "sha512-LvSDNqpmZIZyweFaEQ6wKY7CbexPitlsLHGJtcooNECo0An/w49rFhjCJzu6efeb6+a3ee946xss1Jcd9r03UQ==", + "requires": { + "@jest/source-map": "^25.2.6", + "chalk": "^3.0.0", + "jest-util": "^25.3.0", + "slash": "^3.0.0" + } }, - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" - }, - "jest-message-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", - "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", + "@jest/source-map": { + "version": "25.2.6", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-25.2.6.tgz", + "integrity": "sha512-VuIRZF8M2zxYFGTEhkNSvQkUKafQro4y+mwUxy5ewRqs5N/ynSFUODYp3fy1zCnbCMy1pz3k+u57uCqx8QRSQQ==", "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/stack-utils": "^1.0.1", - "chalk": "^2.0.1", - "micromatch": "^3.1.10", - "slash": "^2.0.0", - "stack-utils": "^1.0.1" + "callsites": "^3.0.0", + "graceful-fs": "^4.2.3", + "source-map": "^0.6.0" } }, - "jest-mock": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz", - "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", + "@jest/test-result": { + "version": "25.3.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-25.3.0.tgz", + "integrity": "sha512-mqrGuiiPXl1ap09Mydg4O782F3ouDQfsKqtQzIjitpwv3t1cHDwCto21jThw6WRRE+dKcWQvLG70GpyLJICfGw==", "requires": { - "@jest/types": "^24.9.0" + "@jest/console": "^25.3.0", + "@jest/types": "^25.3.0", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" } }, - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==" + "@jest/transform": { + "version": "25.3.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-25.3.0.tgz", + "integrity": "sha512-W01p8kTDvvEX6kd0tJc7Y5VdYyFaKwNWy1HQz6Jqlhu48z/8Gxp+yFCDVj+H8Rc7ezl3Mg0hDaGuFVkmHOqirg==", + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^25.3.0", + "babel-plugin-istanbul": "^6.0.0", + "chalk": "^3.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.3", + "jest-haste-map": "^25.3.0", + "jest-regex-util": "^25.2.6", + "jest-util": "^25.3.0", + "micromatch": "^4.0.2", + "pirates": "^4.0.1", + "realpath-native": "^2.0.0", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + } }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "@jest/fake-timers": { - "version": "24.7.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.7.1.tgz", - "integrity": "sha512-4vSQJDKfR2jScOe12L9282uiwuwQv9Lk7mgrCSZHA9evB9efB/qx8i0KJxsAKtp8fgJYBJdYY7ZU6u3F4/pyjA==", - "requires": { - "@jest/types": "^24.7.0", - "jest-message-util": "^24.7.1", - "jest-mock": "^24.7.0" - } - }, - "@jest/reporters": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-24.9.0.tgz", - "integrity": "sha512-mu4X0yjaHrffOsWmVLzitKmmmWSQ3GGuefgNscUSWNiUNcEOSEQk9k3pERKEQVBb0Cnn88+UESIsZEMH3o88Gw==", - "requires": { - "@jest/environment": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "glob": "^7.1.2", - "istanbul-lib-coverage": "^2.0.2", - "istanbul-lib-instrument": "^3.0.1", - "istanbul-lib-report": "^2.0.4", - "istanbul-lib-source-maps": "^3.0.1", - "istanbul-reports": "^2.2.6", - "jest-haste-map": "^24.9.0", - "jest-resolve": "^24.9.0", - "jest-runtime": "^24.9.0", - "jest-util": "^24.9.0", - "jest-worker": "^24.6.0", - "node-notifier": "^5.4.2", - "slash": "^2.0.0", - "source-map": "^0.6.0", - "string-length": "^2.0.0" - }, - "dependencies": { - "@jest/console": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", - "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", "requires": { - "@jest/source-map": "^24.9.0", - "chalk": "^2.0.1", - "slash": "^2.0.0" + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" } }, - "@jest/fake-timers": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz", - "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", "requires": { - "@jest/types": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-mock": "^24.9.0" + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" } }, - "@jest/source-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", - "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", + "babel-plugin-istanbul": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", + "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==", "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.1.15", - "source-map": "^0.6.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^4.0.0", + "test-exclude": "^6.0.0" } }, - "@jest/test-result": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", - "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "requires": { - "@jest/console": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/istanbul-lib-coverage": "^2.0.0" + "fill-range": "^7.0.1" } }, - "@jest/types": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", - "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^13.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "@types/yargs": { - "version": "13.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.4.tgz", - "integrity": "sha512-Ke1WmBbIkVM8bpvsNEcGgQM70XcEh/nbpxQhW7FhrsbCsXSY9BmLB1+LHtD7r9zrsOcFlLiF+a/UeJsdfw3C5A==", + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "requires": { - "@types/yargs-parser": "*" + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" } }, + "fsevents": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz", + "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==", + "optional": true + }, "graceful-fs": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "is-wsl": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.1.1.tgz", + "integrity": "sha512-umZHcSrwlDHo2TGMXv0DZ8dIUGunZ2Iv68YZnrmCiBPkZ4aaOhtv7pXJKeki9k3qJ3RJr0cDyitcl5wEH3AYog==", + "optional": true + }, "istanbul-reports": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.6.tgz", - "integrity": "sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", + "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", "requires": { - "handlebars": "^4.1.2" + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" } }, "jest-haste-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.9.0.tgz", - "integrity": "sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ==", + "version": "25.3.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-25.3.0.tgz", + "integrity": "sha512-LjXaRa+F8wwtSxo9G+hHD/Cp63PPQzvaBL9XCVoJD2rrcJO0Zr2+YYzAFWWYJ5GlPUkoaJFJtOuk0sL6MJY80A==", "requires": { - "@jest/types": "^24.9.0", - "anymatch": "^2.0.0", + "@jest/types": "^25.3.0", + "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", - "fsevents": "^1.2.7", - "graceful-fs": "^4.1.15", - "invariant": "^2.2.4", - "jest-serializer": "^24.9.0", - "jest-util": "^24.9.0", - "jest-worker": "^24.9.0", - "micromatch": "^3.1.10", + "fsevents": "^2.1.2", + "graceful-fs": "^4.2.3", + "jest-serializer": "^25.2.6", + "jest-util": "^25.3.0", + "jest-worker": "^25.2.6", + "micromatch": "^4.0.2", "sane": "^4.0.3", - "walker": "^1.0.7" - }, - "dependencies": { - "jest-worker": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", - "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", - "requires": { - "merge-stream": "^2.0.0", - "supports-color": "^6.1.0" - } - } - } - }, - "jest-message-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", - "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", - "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/stack-utils": "^1.0.1", - "chalk": "^2.0.1", - "micromatch": "^3.1.10", - "slash": "^2.0.0", - "stack-utils": "^1.0.1" + "walker": "^1.0.7", + "which": "^2.0.2" } }, - "jest-mock": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz", - "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", - "requires": { - "@jest/types": "^24.9.0" - } + "jest-regex-util": { + "version": "25.2.6", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-25.2.6.tgz", + "integrity": "sha512-KQqf7a0NrtCkYmZZzodPftn7fL1cq3GQAFVMn5Hg8uKx/fIenLEobNanUxb7abQ1sjADHBseG/2FGpsv/wr+Qw==" }, "jest-resolve": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.9.0.tgz", - "integrity": "sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ==", + "version": "25.3.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-25.3.0.tgz", + "integrity": "sha512-IHoQAAybulsJ+ZgWis+ekYKDAoFkVH5Nx/znpb41zRtpxj4fr2WNV9iDqavdSm8GIpMlsfZxbC/fV9DhW0q9VQ==", "requires": { - "@jest/types": "^24.9.0", + "@jest/types": "^25.3.0", "browser-resolve": "^1.11.3", - "chalk": "^2.0.1", + "chalk": "^3.0.0", "jest-pnp-resolver": "^1.2.1", - "realpath-native": "^1.1.0" + "realpath-native": "^2.0.0", + "resolve": "^1.15.1" } }, "jest-serializer": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.9.0.tgz", - "integrity": "sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ==" + "version": "25.2.6", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-25.2.6.tgz", + "integrity": "sha512-RMVCfZsezQS2Ww4kB5HJTMaMJ0asmC0BHlnobQC6yEtxiFKIxohFA4QSXSabKwSggaNkqxn6Z2VwdFCjhUWuiQ==" }, "jest-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz", - "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", + "version": "25.3.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-25.3.0.tgz", + "integrity": "sha512-dc625P/KS/CpWTJJJxKc4bA3A6c+PJGBAqS8JTJqx4HqPoKNqXg/Ec8biL2Z1TabwK7E7Ilf0/ukSEXM1VwzNA==", "requires": { - "@jest/console": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/source-map": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "callsites": "^3.0.0", - "chalk": "^2.0.1", - "graceful-fs": "^4.1.15", + "@jest/types": "^25.3.0", + "chalk": "^3.0.0", "is-ci": "^2.0.0", - "mkdirp": "^0.5.1", - "slash": "^2.0.0", - "source-map": "^0.6.0" + "make-dir": "^3.0.0" + } + }, + "jest-worker": { + "version": "25.2.6", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-25.2.6.tgz", + "integrity": "sha512-FJn9XDUSxcOR4cwDzRfL1z56rUofNTFs539FGASpd50RHdb6EVkhxQqktodW2mI49l+W3H+tFJDotCHUQF6dmA==", + "requires": { + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" } }, "merge-stream": { @@ -3079,27 +2743,72 @@ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" }, + "micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + } + }, "node-notifier": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.3.tgz", - "integrity": "sha512-M4UBGcs4jeOK9CjTsYwkvH6/MzuUmGCyTW+kCY7uO+1ZVr0+FHGdPdIf5CCLqAaxnRrWidyoQlNkMIIVwbKB8Q==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-6.0.0.tgz", + "integrity": "sha512-SVfQ/wMw+DesunOm5cKqr6yDcvUTDl/yc97ybGHMrteNEY6oekXpNpS3lZwgLlwz0FLgHoiW28ZpmBHUDg37cw==", + "optional": true, "requires": { "growly": "^1.3.0", - "is-wsl": "^1.1.0", - "semver": "^5.5.0", + "is-wsl": "^2.1.1", + "semver": "^6.3.0", "shellwords": "^0.1.1", - "which": "^1.3.0" + "which": "^1.3.1" + }, + "dependencies": { + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "optional": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + }, + "realpath-native": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-2.0.0.tgz", + "integrity": "sha512-v1SEYUOXXdbBZK8ZuNgO4TBjamPsiSgcFr0aP+tEKpQZK8vooEUqV6nm6Cv502mX4NF2EfsnVqtNAHG+/6Ur1Q==" + }, + "resolve": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", + "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", + "requires": { + "path-parse": "^1.0.6" } }, "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "optional": true }, "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" }, "source-map": { "version": "0.6.1", @@ -3107,29 +2816,71 @@ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" + } + }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "dependencies": { + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" } }, "write-file-atomic": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.1.tgz", - "integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", "requires": { - "graceful-fs": "^4.1.11", "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" } } } }, "@jest/source-map": { - "version": "24.3.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.3.0.tgz", - "integrity": "sha512-zALZt1t2ou8le/crCeeiRYzvdnTzaIlpOWaet45lNSqNJUnXbppUUFR4ZUAlzgDmKee4Q5P/tKXypI1RiHwgag==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", + "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", "requires": { "callsites": "^3.0.0", "graceful-fs": "^4.1.15", @@ -3137,9 +2888,9 @@ }, "dependencies": { "graceful-fs": { - "version": "4.1.15", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", - "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==" + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" }, "source-map": { "version": "0.6.1", @@ -3149,66 +2900,15 @@ } }, "@jest/test-result": { - "version": "24.7.1", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.7.1.tgz", - "integrity": "sha512-3U7wITxstdEc2HMfBX7Yx3JZgiNBubwDqQMh+BXmZXHa3G13YWF3p6cK+5g0hGkN3iufg/vGPl3hLxQXD74Npg==", - "requires": { - "@jest/console": "^24.7.1", - "@jest/types": "^24.7.0", - "@types/istanbul-lib-coverage": "^2.0.0" - } - }, - "@jest/test-sequencer": { "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-24.9.0.tgz", - "integrity": "sha512-6qqsU4o0kW1dvA95qfNog8v8gkRN9ph6Lz7r96IvZpHdNipP2cBcb07J1Z45mz/VIS01OHJ3pY8T5fUY38tg4A==", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", + "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", "requires": { - "@jest/test-result": "^24.9.0", - "jest-haste-map": "^24.9.0", - "jest-runner": "^24.9.0", - "jest-runtime": "^24.9.0" + "@jest/console": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/istanbul-lib-coverage": "^2.0.0" }, "dependencies": { - "@jest/console": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", - "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", - "requires": { - "@jest/source-map": "^24.9.0", - "chalk": "^2.0.1", - "slash": "^2.0.0" - } - }, - "@jest/fake-timers": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz", - "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", - "requires": { - "@jest/types": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-mock": "^24.9.0" - } - }, - "@jest/source-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", - "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.1.15", - "source-map": "^0.6.0" - } - }, - "@jest/test-result": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", - "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", - "requires": { - "@jest/console": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/istanbul-lib-coverage": "^2.0.0" - } - }, "@jest/types": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", @@ -3220,122 +2920,32 @@ } }, "@types/yargs": { - "version": "13.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.4.tgz", - "integrity": "sha512-Ke1WmBbIkVM8bpvsNEcGgQM70XcEh/nbpxQhW7FhrsbCsXSY9BmLB1+LHtD7r9zrsOcFlLiF+a/UeJsdfw3C5A==", + "version": "13.0.8", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz", + "integrity": "sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA==", "requires": { "@types/yargs-parser": "*" } - }, - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" - }, - "jest-haste-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.9.0.tgz", - "integrity": "sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ==", - "requires": { - "@jest/types": "^24.9.0", - "anymatch": "^2.0.0", - "fb-watchman": "^2.0.0", - "fsevents": "^1.2.7", - "graceful-fs": "^4.1.15", - "invariant": "^2.2.4", - "jest-serializer": "^24.9.0", - "jest-util": "^24.9.0", - "jest-worker": "^24.9.0", - "micromatch": "^3.1.10", - "sane": "^4.0.3", - "walker": "^1.0.7" - } - }, - "jest-message-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", - "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", - "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/stack-utils": "^1.0.1", - "chalk": "^2.0.1", - "micromatch": "^3.1.10", - "slash": "^2.0.0", - "stack-utils": "^1.0.1" - } - }, - "jest-mock": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz", - "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", - "requires": { - "@jest/types": "^24.9.0" - } - }, - "jest-serializer": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.9.0.tgz", - "integrity": "sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ==" - }, - "jest-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz", - "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", - "requires": { - "@jest/console": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/source-map": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "callsites": "^3.0.0", - "chalk": "^2.0.1", - "graceful-fs": "^4.1.15", - "is-ci": "^2.0.0", - "mkdirp": "^0.5.1", - "slash": "^2.0.0", - "source-map": "^0.6.0" - } - }, - "jest-worker": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", - "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", - "requires": { - "merge-stream": "^2.0.0", - "supports-color": "^6.1.0" - } - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" - }, - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } } } }, + "@jest/test-sequencer": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-24.9.0.tgz", + "integrity": "sha512-6qqsU4o0kW1dvA95qfNog8v8gkRN9ph6Lz7r96IvZpHdNipP2cBcb07J1Z45mz/VIS01OHJ3pY8T5fUY38tg4A==", + "dev": true, + "requires": { + "@jest/test-result": "^24.9.0", + "jest-haste-map": "^24.9.0", + "jest-runner": "^24.9.0", + "jest-runtime": "^24.9.0" + } + }, "@jest/transform": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-24.9.0.tgz", "integrity": "sha512-TcQUmyNRxV94S0QpMOnZl0++6RMiqpbH/ZMccFB/amku6Uwvyb1cjYX7xkp5nGNkbX4QPH/FcB6q1HBTHynLmQ==", + "dev": true, "requires": { "@babel/core": "^7.1.0", "@jest/types": "^24.9.0", @@ -3355,50 +2965,11 @@ "write-file-atomic": "2.4.1" }, "dependencies": { - "@jest/console": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", - "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", - "requires": { - "@jest/source-map": "^24.9.0", - "chalk": "^2.0.1", - "slash": "^2.0.0" - } - }, - "@jest/fake-timers": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz", - "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", - "requires": { - "@jest/types": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-mock": "^24.9.0" - } - }, - "@jest/source-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", - "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.1.15", - "source-map": "^0.6.0" - } - }, - "@jest/test-result": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", - "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", - "requires": { - "@jest/console": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/istanbul-lib-coverage": "^2.0.0" - } - }, "@jest/types": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^1.1.1", @@ -3406,142 +2977,113 @@ } }, "@types/yargs": { - "version": "13.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.4.tgz", - "integrity": "sha512-Ke1WmBbIkVM8bpvsNEcGgQM70XcEh/nbpxQhW7FhrsbCsXSY9BmLB1+LHtD7r9zrsOcFlLiF+a/UeJsdfw3C5A==", + "version": "13.0.8", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz", + "integrity": "sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA==", + "dev": true, "requires": { "@types/yargs-parser": "*" } }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, "graceful-fs": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", + "dev": true }, - "jest-haste-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.9.0.tgz", - "integrity": "sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ==", + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "write-file-atomic": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.1.tgz", + "integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==", + "dev": true, "requires": { - "@jest/types": "^24.9.0", - "anymatch": "^2.0.0", - "fb-watchman": "^2.0.0", - "fsevents": "^1.2.7", - "graceful-fs": "^4.1.15", - "invariant": "^2.2.4", - "jest-serializer": "^24.9.0", - "jest-util": "^24.9.0", - "jest-worker": "^24.9.0", - "micromatch": "^3.1.10", - "sane": "^4.0.3", - "walker": "^1.0.7" + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + } + } + }, + "@jest/types": { + "version": "25.3.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.3.0.tgz", + "integrity": "sha512-UkaDNewdqXAmCDbN2GlUM6amDKS78eCqiw/UmF5nE0mmLTd6moJkiZJML/X52Ke3LH7Swhw883IRXq8o9nWjVw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^15.0.0", + "chalk": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" } }, - "jest-message-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", - "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/stack-utils": "^1.0.1", - "chalk": "^2.0.1", - "micromatch": "^3.1.10", - "slash": "^2.0.0", - "stack-utils": "^1.0.1" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "jest-mock": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz", - "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "requires": { - "@jest/types": "^24.9.0" + "color-name": "~1.1.4" } }, - "jest-regex-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz", - "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==" - }, - "jest-serializer": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.9.0.tgz", - "integrity": "sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ==" - }, - "jest-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz", - "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", - "requires": { - "@jest/console": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/source-map": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "callsites": "^3.0.0", - "chalk": "^2.0.1", - "graceful-fs": "^4.1.15", - "is-ci": "^2.0.0", - "mkdirp": "^0.5.1", - "slash": "^2.0.0", - "source-map": "^0.6.0" - } - }, - "jest-worker": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", - "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", - "requires": { - "merge-stream": "^2.0.0", - "supports-color": "^6.1.0" - } - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" - }, - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==" + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - }, - "write-file-atomic": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.1.tgz", - "integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" + "has-flag": "^4.0.0" } } } }, - "@jest/types": { - "version": "24.7.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.7.0.tgz", - "integrity": "sha512-ipJUa2rFWiKoBqMKP63Myb6h9+iT3FHRTF2M8OR6irxWzItisa8i4dcSg14IbvmXUnBlHBlUQPYUHWyX3UPpYA==", - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/yargs": "^12.0.9" - } - }, "@lerna/add": { "version": "3.18.0", "resolved": "https://registry.npmjs.org/@lerna/add/-/add-3.18.0.tgz", @@ -3660,6 +3202,17 @@ "strong-log-transformer": "^2.0.0" }, "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -3942,6 +3495,19 @@ "chalk": "^2.3.1", "figgy-pudding": "^3.5.1", "npmlog": "^4.1.2" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } } }, "@lerna/collect-updates": { @@ -4708,6 +4274,19 @@ "@lerna/query-graph": "3.18.0", "chalk": "^2.3.1", "columnify": "^1.5.4" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } } }, "@lerna/log-packed": { @@ -5258,6 +4837,19 @@ "string-width": "^2.1.0", "strip-ansi": "^5.1.0", "through": "^2.3.6" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } } }, "strip-ansi": { @@ -5399,6 +4991,31 @@ "npmlog": "^4.1.2", "path-exists": "^3.0.0", "rimraf": "^2.6.2" + }, + "dependencies": { + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } } }, "@lerna/run": { @@ -5574,6 +5191,17 @@ "write-json-file": "^3.2.0" }, "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, "graceful-fs": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", @@ -5809,6 +5437,19 @@ "chalk": "^2.0.0", "esutils": "^2.0.2", "js-tokens": "^4.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } } }, "@babel/parser": { @@ -6292,6 +5933,11 @@ } } }, + "@popperjs/core": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.1.1.tgz", + "integrity": "sha512-sLqWxCzC5/QHLhziXSCAksBxHfOnQlhPRVgPK0egEw+ktWvG75T2k+aYWVjVh9+WKeT3tlG3ZNbZQvZLmfuOIw==" + }, "@reach/router": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@reach/router/-/router-1.2.1.tgz", @@ -6327,6 +5973,16 @@ "xmldoc": "^1.1.2" }, "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -6391,6 +6047,18 @@ "chalk": "^2.4.2", "js-yaml": "^3.13.1", "xcode": "^2.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } } }, "@react-native-community/cli-tools": { @@ -6404,6 +6072,16 @@ "node-fetch": "^2.5.0" }, "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, "node-fetch": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", @@ -6429,6 +6107,19 @@ "any-observable": "^0.3.0" } }, + "@sindresorhus/is": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-2.1.0.tgz", + "integrity": "sha512-lXKXfypKo644k4Da4yXkPCrwcvn6SlUW2X2zFbuflKHNjf0w9htru01bo26uMhleMXsDmnZ12eJLdrAZa9MANg==" + }, + "@sinonjs/commons": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.7.2.tgz", + "integrity": "sha512-+DUO6pnp3udV/v2VfUWgaY5BIE1IfT7lLfeDzPVeMT1XKkaAp9LgSI9x5RtrFQoZ9Oi0PgXQQHPaoKu7dCjVxw==", + "requires": { + "type-detect": "4.0.8" + } + }, "@storybook/addon-a11y": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/@storybook/addon-a11y/-/addon-a11y-5.3.2.tgz", @@ -6602,182 +6293,6 @@ } } }, - "@storybook/addon-storyshots": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/@storybook/addon-storyshots/-/addon-storyshots-5.3.2.tgz", - "integrity": "sha512-83imS+T5UVthV246FCD468lYWJjqDXPjAafDegJ5a2BDFkQvsNpIYU3E4qpLM9c6I8tVPAf/o7KMwkXC2ciXqA==", - "dev": true, - "requires": { - "@jest/transform": "^24.9.0", - "@storybook/addons": "5.3.2", - "@storybook/client-api": "5.3.2", - "@storybook/core": "5.3.2", - "@types/glob": "^7.1.1", - "@types/jest": "^24.0.16", - "@types/jest-specific-snapshot": "^0.5.3", - "babel-plugin-require-context-hook": "^1.0.0", - "core-js": "^3.0.1", - "glob": "^7.1.3", - "global": "^4.3.2", - "jest-specific-snapshot": "^2.0.0", - "read-pkg-up": "^7.0.0", - "regenerator-runtime": "^0.13.3", - "ts-dedent": "^1.1.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "p-limit": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", - "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "parse-json": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", - "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1", - "lines-and-columns": "^1.1.6" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", - "dev": true - }, - "read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "requires": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "dependencies": { - "type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true - } - } - }, - "read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "requires": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - } - }, - "regenerator-runtime": { - "version": "0.13.3", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", - "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==", - "dev": true - }, - "resolve": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.0.tgz", - "integrity": "sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw==", - "dev": true, - "requires": { - "path-parse": "^1.0.6" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true - } - } - }, "@storybook/addon-storysource": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/@storybook/addon-storysource/-/addon-storysource-5.3.2.tgz", @@ -9000,6 +8515,19 @@ "stable": "^0.1.8", "unquote": "~1.1.1", "util.promisify": "~1.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } } } } @@ -9503,6 +9031,18 @@ "stable": "^0.1.8", "unquote": "~1.1.1", "util.promisify": "~1.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } } } } @@ -9552,32 +9092,157 @@ } } }, + "@szmarczak/http-timer": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.5.tgz", + "integrity": "sha512-PyRA9sm1Yayuj5OIoJ1hGt2YISX45w9WcFbh6ddT0Z/0yaFxOtGLInr4jUfU1EAFVs0Yfyfev4RNwBlUaHdlDQ==", + "requires": { + "defer-to-connect": "^2.0.0" + } + }, "@tannin/compile": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tannin/compile/-/compile-1.0.3.tgz", - "integrity": "sha512-OkPHvaM/hIHdSco3+ZO1hzkOtfEddn5a0veWft2aDLvKnbdj9VusiLKNdEE9by3hCZIIcb9aWF+iBorhfrQOfw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@tannin/compile/-/compile-1.1.0.tgz", + "integrity": "sha512-n8m9eNDfoNZoxdvWiTfW/hSPhehzLJ3zW7f8E7oT6mCROoMNWCB4TYtv041+2FMAxweiE0j7i1jubQU4MEC/Gg==", "requires": { - "@tannin/evaluate": "^1.1.1", - "@tannin/postfix": "^1.0.2" + "@tannin/evaluate": "^1.2.0", + "@tannin/postfix": "^1.1.0" } }, "@tannin/evaluate": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@tannin/evaluate/-/evaluate-1.1.1.tgz", - "integrity": "sha512-ALuSZHjrLHGnw0WxsHDHde74FJ2WW0Ck4rg3QBxFBCmxd6Wsac+e0HXfJ++Qion15LIOCmFhyVpWzawMgeBA8Q==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@tannin/evaluate/-/evaluate-1.2.0.tgz", + "integrity": "sha512-3ioXvNowbO/wSrxsDG5DKIMxC81P0QrQTYai8zFNY+umuoHWRPbQ/TuuDEOju9E+jQDXmj6yI5GyejNuh8I+eg==" }, "@tannin/plural-forms": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tannin/plural-forms/-/plural-forms-1.0.3.tgz", - "integrity": "sha512-IUr9+FiCnzCiB9aRio3FVNR8TNL9SmX2zkV6tmfWWwSclX4uTCykoGsDhTGKK+sZnMrdPCTmb/OxbtGNdVyV4g==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@tannin/plural-forms/-/plural-forms-1.1.0.tgz", + "integrity": "sha512-xl9R2mDZO/qiHam1AgMnAES6IKIg7OBhcXqy6eDsRCdXuxAFPcjrej9HMjyCLE0DJ/8cHf0i5OQTstuBRhpbHw==", "requires": { - "@tannin/compile": "^1.0.3" + "@tannin/compile": "^1.1.0" } }, "@tannin/postfix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@tannin/postfix/-/postfix-1.0.2.tgz", - "integrity": "sha512-Nggtk7/ljfNPpAX8CjxxLkMKuO6u2gH1ozmTvGclWF2pNcxTf6YGghYNYNWZRKrimXGhQ8yZqvAHep7h80K04g==" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@tannin/postfix/-/postfix-1.1.0.tgz", + "integrity": "sha512-oocsqY7g0cR+Gur5jRQLSrX2OtpMLMse1I10JQBm8CdGMrDkh1Mg2gjsiquMHRtBs4Qwu5wgEp5GgIYHk4SNPw==" + }, + "@testing-library/dom": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.2.1.tgz", + "integrity": "sha512-xIGoHlQ2ZiEL1dJIFKNmLDypzYF+4OJTTASRctl/aoIDaS5y/pRVHRigoqvPUV11mdJoR71IIgi/6UviMgyz4g==", + "dev": true, + "requires": { + "@babel/runtime": "^7.9.2", + "@types/testing-library__dom": "^7.0.0", + "aria-query": "^4.0.2", + "dom-accessibility-api": "^0.4.2", + "pretty-format": "^25.1.0" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.9.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.2.tgz", + "integrity": "sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "aria-query": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.0.2.tgz", + "integrity": "sha512-S1G1V790fTaigUSM/Gd0NngzEfiMy9uTUfMyHhKhVyy4cH5O/eTuR01ydhGL0z4Za1PXFTRGH3qL8VhUQuEO5w==", + "dev": true, + "requires": { + "@babel/runtime": "^7.7.4", + "@babel/runtime-corejs3": "^7.7.4" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "pretty-format": { + "version": "25.3.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.3.0.tgz", + "integrity": "sha512-wToHwF8bkQknIcFkBqNfKu4+UZqnrLn/Vr+wwKQwwvPzkBfDDKp/qIabFqdgtoi5PEnM8LFByVsOrHoa3SpTVA==", + "dev": true, + "requires": { + "@jest/types": "^25.3.0", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^16.12.0" + } + }, + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + }, + "regenerator-runtime": { + "version": "0.13.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz", + "integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==", + "dev": true + } + } + }, + "@testing-library/react": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-10.0.2.tgz", + "integrity": "sha512-YT6Mw0oJz7R6vlEkmo1FlUD+K15FeXApOB5Ffm9zooFVnrwkt00w18dUJFMOh1yRp9wTdVRonbor7o4PIpFCmA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.9.2", + "@testing-library/dom": "^7.1.0", + "@types/testing-library__react": "^10.0.0" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.9.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.2.tgz", + "integrity": "sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "regenerator-runtime": { + "version": "0.13.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz", + "integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==", + "dev": true + } + } }, "@types/babel-types": { "version": "7.0.7", @@ -9586,9 +9251,9 @@ "dev": true }, "@types/babel__core": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.3.tgz", - "integrity": "sha512-8fBo0UR2CcwWxeX7WIIgJ7lXjasFxoYgRnFHUj+hRvKkpiBJbxhdAPTCY6/ZKM0uxANFVzt4yObSLuTiTnazDA==", + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.7.tgz", + "integrity": "sha512-RL62NqSFPCDK2FM1pSDH0scHpJvsXtZNiYlMB73DgPBaG1E38ZYVL+ei5EkWRbr+KC4YNiAUNBnRj+bgwpgjMw==", "requires": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0", @@ -9598,9 +9263,9 @@ } }, "@types/babel__generator": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.0.tgz", - "integrity": "sha512-c1mZUu4up5cp9KROs/QAw0gTeHrw/x7m52LcnvMxxOZ03DmLwPV0MlGmlgzV3cnSdjhJOZsj7E7FHeioai+egw==", + "version": "7.6.1", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.1.tgz", + "integrity": "sha512-bBKm+2VPJcMRVwNhxKu8W+5/zT7pwNEqeokFOmbvVSqGzFneNxYcEBro9Ac7/N9tlsaPYnZLK8J1LWKkMsLAew==", "requires": { "@babel/types": "^7.0.0" } @@ -9615,9 +9280,9 @@ } }, "@types/babel__traverse": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.7.tgz", - "integrity": "sha512-CeBpmX1J8kWLcDEnI3Cl2Eo6RfbGvzUctA+CjZUhOKDFbLfcr7fc4usEqLNWetrlJd7RhAkyYe2czXop4fICpw==", + "version": "7.0.10", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.10.tgz", + "integrity": "sha512-74fNdUGrWsgIB/V9kTO5FGHPWYY6Eqn+3Z7L6Hc4e/BxjYV7puvBqp5HwsVYYfLm6iURYBNCx4Ut37OF9yitCw==", "requires": { "@babel/types": "^7.3.0" } @@ -9631,11 +9296,27 @@ "@types/babel-types": "*" } }, + "@types/cacheable-request": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.1.tgz", + "integrity": "sha512-ykFq2zmBGOCbpIXtoVbz4SKY5QriWPh3AjyU4G74RYbtt5yOc5OfaY75ftjg7mikMOla1CTGpX3lLbuJh8DTrQ==", + "requires": { + "@types/http-cache-semantics": "*", + "@types/keyv": "*", + "@types/node": "*", + "@types/responselike": "*" + } + }, + "@types/classnames": { + "version": "2.2.10", + "resolved": "https://registry.npmjs.org/@types/classnames/-/classnames-2.2.10.tgz", + "integrity": "sha512-1UzDldn9GfYYEsWWnn/P4wkTlkZDH7lDb0wBMGbtIQc9zXEQq7FlKBdZUn6OBqD8sKZZ2RQO2mAjGpXiDGoRmQ==", + "dev": true + }, "@types/color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", - "dev": true + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" }, "@types/events": { "version": "3.0.0", @@ -9658,6 +9339,11 @@ "integrity": "sha512-+o2igcuZA3xtOoFH56s+MCZVidwlJNcJID57DSCyawS2i910yG9vkwehCjJNZ6ImhCR5S9DbvIJKyYHcMyOfMw==", "dev": true }, + "@types/http-cache-semantics": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz", + "integrity": "sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A==" + }, "@types/is-function": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/is-function/-/is-function-1.0.0.tgz", @@ -9686,34 +9372,40 @@ "@types/istanbul-lib-report": "*" } }, - "@types/jest": { - "version": "24.0.25", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-24.0.25.tgz", - "integrity": "sha512-hnP1WpjN4KbGEK4dLayul6lgtys6FPz0UfxMeMQCv0M+sTnzN3ConfiO72jHgLxl119guHgI8gLqDOrRLsyp2g==", - "dev": true, - "requires": { - "jest-diff": "^24.3.0" - } + "@types/json-schema": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.4.tgz", + "integrity": "sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA==" }, - "@types/jest-specific-snapshot": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/@types/jest-specific-snapshot/-/jest-specific-snapshot-0.5.4.tgz", - "integrity": "sha512-1qISn4fH8wkOOPFEx+uWRRjw6m/pP/It3OHLm8Ee1KQpO7Z9ZGYDtWPU5AgK05UXsNTAgOK+dPQvJKGdy9E/1g==", - "dev": true, + "@types/keyv": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.1.tgz", + "integrity": "sha512-MPtoySlAZQ37VoLaPcTHCu1RWJ4llDkULYZIzOYxlhxBqYPB0RsRlmMU0R6tahtFe27mIdkHV+551ZWV4PLmVw==", "requires": { - "@types/jest": "*" + "@types/node": "*" } }, - "@types/json-schema": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.3.tgz", - "integrity": "sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A==" + "@types/lodash": { + "version": "4.14.149", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.149.tgz", + "integrity": "sha512-ijGqzZt/b7BfzcK9vTrS6MFljQRPn5BFWOx8oE0GYxribu6uV+aA9zZuXI1zc/etK9E8nrgdoF2+LgUw7+9tJQ==", + "dev": true + }, + "@types/mime-types": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.0.tgz", + "integrity": "sha1-nKUs2jY/aZxpRmwqbM2q2RPqenM=" }, "@types/minimatch": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==" }, + "@types/minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY=" + }, "@types/node": { "version": "12.7.11", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.11.tgz", @@ -9722,14 +9414,18 @@ "@types/normalize-package-data": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", - "dev": true + "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==" }, "@types/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" }, + "@types/prettier": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-1.19.0.tgz", + "integrity": "sha512-gDE8JJEygpay7IjA/u3JiIURvwZW08f0cZSZLAzFoX/ZmeqvS0Sqv+97aKuHpNsalAMMhwPe+iAS6fQbfmbt7A==" + }, "@types/prop-types": { "version": "15.7.3", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", @@ -9740,6 +9436,12 @@ "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz", "integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==" }, + "@types/qs": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.1.tgz", + "integrity": "sha512-lhbQXx9HKZAPgBkISrBcmAcMpZsmpe/Cd/hY7LGZS5OfkySUBItnPZHgQPssWYUET8elF+yCFBbP1Q0RZPTdaw==", + "dev": true + }, "@types/reach__router": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/@types/reach__router/-/reach__router-1.2.6.tgz", @@ -9768,6 +9470,15 @@ "@types/react": "*" } }, + "@types/react-dom": { + "version": "16.9.5", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.5.tgz", + "integrity": "sha512-BX6RQ8s9D+2/gDhxrj8OW+YD4R+8hj7FEM/OJHGNR0KipE1h1mSsf39YeyC81qafkq+N3rU3h3RFbLSwE5VqUg==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, "@types/react-native": { "version": "0.57.65", "resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.57.65.tgz", @@ -9801,11 +9512,147 @@ "integrity": "sha512-BnnRkgWYijCIndUn+LgoqKHX/hNpJC5G03B9y7mZya/C2gUQTSn75fEj3ZP1/Rl2E6EYeXh2/7/8UNEZ4X7HuQ==", "dev": true }, + "@types/responselike": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", + "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", + "requires": { + "@types/node": "*" + } + }, + "@types/sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@types/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-hkgzYF+qnIl8uTO8rmUSVSfQ8BIfMXC4yJAF4n8BE758YsKBZvFC4NumnAegj7KmylP0liEZNpb9RRGFMbFejA==", + "dev": true + }, "@types/stack-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==" }, + "@types/testing-library__dom": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@types/testing-library__dom/-/testing-library__dom-7.0.1.tgz", + "integrity": "sha512-WokGRksRJb3Dla6h02/0/NNHTkjsj4S8aJZiwMj/5/UL8VZ1iCe3H8SHzfpmBeH8Vp4SPRT8iC2o9kYULFhDIw==", + "dev": true, + "requires": { + "pretty-format": "^25.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "pretty-format": { + "version": "25.3.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.3.0.tgz", + "integrity": "sha512-wToHwF8bkQknIcFkBqNfKu4+UZqnrLn/Vr+wwKQwwvPzkBfDDKp/qIabFqdgtoi5PEnM8LFByVsOrHoa3SpTVA==", + "dev": true, + "requires": { + "@jest/types": "^25.3.0", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^16.12.0" + } + }, + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + } + } + }, + "@types/testing-library__react": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@types/testing-library__react/-/testing-library__react-10.0.1.tgz", + "integrity": "sha512-RbDwmActAckbujLZeVO/daSfdL1pnjVqas25UueOkAY5r7vriavWf0Zqg7ghXMHa8ycD/kLkv8QOj31LmSYwww==", + "dev": true, + "requires": { + "@types/react-dom": "*", + "@types/testing-library__dom": "*", + "pretty-format": "^25.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "pretty-format": { + "version": "25.3.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.3.0.tgz", + "integrity": "sha512-wToHwF8bkQknIcFkBqNfKu4+UZqnrLn/Vr+wwKQwwvPzkBfDDKp/qIabFqdgtoi5PEnM8LFByVsOrHoa3SpTVA==", + "dev": true, + "requires": { + "@jest/types": "^25.3.0", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^16.12.0" + } + }, + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + } + } + }, "@types/unist": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz", @@ -9837,38 +9684,106 @@ "dev": true }, "@types/yargs": { - "version": "12.0.13", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-12.0.13.tgz", - "integrity": "sha512-CXlavd8Q7ZQkB7sMpx9QKC/B7gUsjtftxMHNr7qGJaDiZZ+Qmhwe4Zt3aS9aXF7cn6BYQuFlKU1UlrebyKsh9g==" + "version": "15.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.4.tgz", + "integrity": "sha512-9T1auFmbPZoxHz0enUFlUuKRy3it01R+hlggyVUMtnCTQRunsQYifnSGb8hET4Xo8yiC0o0r1paW3ud5+rbURg==", + "requires": { + "@types/yargs-parser": "*" + } }, "@types/yargs-parser": { "version": "13.1.0", "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-13.1.0.tgz", "integrity": "sha512-gCubfBUZ6KxzoibJ+SCUc/57Ms1jz5NjHe4+dI2krNmU5zCPAphyLJYyTOg06ueIyfj+SaCUqmzun7ImlxDcKg==" }, + "@types/yauzl": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.1.tgz", + "integrity": "sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA==", + "optional": true, + "requires": { + "@types/node": "*" + } + }, "@typescript-eslint/experimental-utils": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-1.13.0.tgz", - "integrity": "sha512-zmpS6SyqG4ZF64ffaJ6uah6tWWWgZ8m+c54XXgwFtUv0jNz8aJAVx8chMCvnk7yl6xwn8d+d96+tWp7fXzTuDg==", + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.26.0.tgz", + "integrity": "sha512-RELVoH5EYd+JlGprEyojUv9HeKcZqF7nZUGSblyAw1FwOGNnmQIU8kxJ69fttQvEwCsX5D6ECJT8GTozxrDKVQ==", "requires": { "@types/json-schema": "^7.0.3", - "@typescript-eslint/typescript-estree": "1.13.0", - "eslint-scope": "^4.0.0" + "@typescript-eslint/typescript-estree": "2.26.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" + }, + "dependencies": { + "eslint-scope": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", + "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + } } }, "@typescript-eslint/typescript-estree": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-1.13.0.tgz", - "integrity": "sha512-b5rCmd2e6DCC6tCTN9GSUAuxdYwCM/k/2wdjHGrIRGPSJotWMCe/dGpi66u42bhuh8q3QBzqM4TMA1GUUCJvdw==", + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.26.0.tgz", + "integrity": "sha512-3x4SyZCLB4zsKsjuhxDLeVJN6W29VwBnYpCsZ7vIdPel9ZqLfIZJgJXO47MNUkurGpQuIBALdPQKtsSnWpE1Yg==", "requires": { - "lodash.unescape": "4.0.1", - "semver": "5.5.0" + "debug": "^4.1.1", + "eslint-visitor-keys": "^1.1.0", + "glob": "^7.1.6", + "is-glob": "^4.0.1", + "lodash": "^4.17.15", + "semver": "^6.3.0", + "tsutils": "^3.17.1" }, "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "eslint-visitor-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==" + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" } } }, @@ -10033,27 +9948,29 @@ "@wordpress/a11y": { "version": "file:packages/a11y", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/dom-ready": "file:packages/dom-ready" } }, "@wordpress/annotations": { "version": "file:packages/annotations", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/data": "file:packages/data", "@wordpress/hooks": "file:packages/hooks", "@wordpress/i18n": "file:packages/i18n", "@wordpress/rich-text": "file:packages/rich-text", "lodash": "^4.17.15", "rememo": "^3.0.0", - "uuid": "^3.3.2" + "uuid": "^7.0.2" } }, "@wordpress/api-fetch": { "version": "file:packages/api-fetch", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", + "@wordpress/deprecated": "file:packages/deprecated", + "@wordpress/element": "file:packages/element", "@wordpress/i18n": "file:packages/i18n", "@wordpress/url": "file:packages/url" } @@ -10061,7 +9978,7 @@ "@wordpress/autop": { "version": "file:packages/autop", "requires": { - "@babel/runtime": "^7.8.3" + "@babel/runtime": "^7.9.2" } }, "@wordpress/babel-plugin-import-jsx-pragma": { @@ -10071,7 +9988,7 @@ "version": "file:packages/babel-plugin-makepot", "dev": true, "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "gettext-parser": "^1.3.1", "lodash": "^4.17.15" } @@ -10079,18 +9996,16 @@ "@wordpress/babel-preset-default": { "version": "file:packages/babel-preset-default", "requires": { - "@babel/core": "^7.8.3", - "@babel/plugin-proposal-async-generator-functions": "^7.8.3", - "@babel/plugin-proposal-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-react-jsx": "^7.8.3", - "@babel/plugin-transform-runtime": "^7.8.3", - "@babel/preset-env": "^7.8.3", - "@babel/runtime": "^7.8.3", + "@babel/core": "^7.9.0", + "@babel/plugin-transform-react-jsx": "^7.9.4", + "@babel/plugin-transform-runtime": "^7.9.0", + "@babel/preset-env": "^7.9.0", + "@babel/runtime": "^7.9.2", "@wordpress/babel-plugin-import-jsx-pragma": "file:packages/babel-plugin-import-jsx-pragma", "@wordpress/browserslist-config": "file:packages/browserslist-config", "@wordpress/element": "file:packages/element", "@wordpress/warning": "file:packages/warning", - "core-js": "^3.1.4" + "core-js": "^3.6.4" } }, "@wordpress/base-styles": { @@ -10100,7 +10015,7 @@ "@wordpress/blob": { "version": "file:packages/blob", "requires": { - "@babel/runtime": "^7.8.3" + "@babel/runtime": "^7.9.2" } }, "@wordpress/block-directory": { @@ -10122,7 +10037,7 @@ "@wordpress/block-editor": { "version": "file:packages/block-editor", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/a11y": "file:packages/a11y", "@wordpress/blob": "file:packages/blob", "@wordpress/blocks": "file:packages/blocks", @@ -10139,6 +10054,7 @@ "@wordpress/is-shallow-equal": "file:packages/is-shallow-equal", "@wordpress/keyboard-shortcuts": "file:packages/keyboard-shortcuts", "@wordpress/keycodes": "file:packages/keycodes", + "@wordpress/priority-queue": "file:packages/priority-queue", "@wordpress/rich-text": "file:packages/rich-text", "@wordpress/token-list": "file:packages/token-list", "@wordpress/url": "file:packages/url", @@ -10150,7 +10066,7 @@ "dom-scroll-into-view": "^1.2.1", "inherits": "^2.0.3", "lodash": "^4.17.15", - "memize": "^1.0.5", + "memize": "^1.1.0", "react-autosize-textarea": "^3.0.2", "react-spring": "^8.0.19", "redux-multi": "^0.1.12", @@ -10163,7 +10079,7 @@ "@wordpress/block-library": { "version": "file:packages/block-library", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/a11y": "file:packages/a11y", "@wordpress/api-fetch": "file:packages/api-fetch", "@wordpress/autop": "file:packages/autop", @@ -10192,7 +10108,7 @@ "classnames": "^2.2.5", "fast-average-color": "4.3.0", "lodash": "^4.17.15", - "memize": "^1.0.5", + "memize": "^1.1.0", "moment": "^2.22.1", "tinycolor2": "^1.4.1" } @@ -10200,7 +10116,7 @@ "@wordpress/block-serialization-default-parser": { "version": "file:packages/block-serialization-default-parser", "requires": { - "@babel/runtime": "^7.8.3" + "@babel/runtime": "^7.9.2" } }, "@wordpress/block-serialization-spec-parser": { @@ -10213,7 +10129,7 @@ "@wordpress/blocks": { "version": "file:packages/blocks", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/autop": "file:packages/autop", "@wordpress/blob": "file:packages/blob", "@wordpress/block-serialization-default-parser": "file:packages/block-serialization-default-parser", @@ -10233,7 +10149,7 @@ "showdown": "^1.8.6", "simple-html-tokenizer": "^0.5.7", "tinycolor2": "^1.4.1", - "uuid": "^3.3.2" + "uuid": "^7.0.2" } }, "@wordpress/browserslist-config": { @@ -10242,7 +10158,7 @@ "@wordpress/components": { "version": "file:packages/components", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@emotion/core": "^10.0.22", "@emotion/css": "^10.0.22", "@emotion/native": "^10.0.22", @@ -10266,21 +10182,21 @@ "downshift": "^4.0.5", "gradient-parser": "^0.1.5", "lodash": "^4.17.15", - "memize": "^1.0.5", + "memize": "^1.1.0", "moment": "^2.22.1", "re-resizable": "^6.0.0", "react-dates": "^17.1.1", "react-spring": "^8.0.20", - "reakit": "^1.0.0-beta.12", + "reakit": "^1.0.0-rc.0", "rememo": "^3.0.0", "tinycolor2": "^1.4.1", - "uuid": "^3.3.2" + "uuid": "^7.0.2" } }, "@wordpress/compose": { "version": "file:packages/compose", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/element": "file:packages/element", "@wordpress/is-shallow-equal": "file:packages/is-shallow-equal", "lodash": "^4.17.15", @@ -10291,10 +10207,11 @@ "@wordpress/core-data": { "version": "file:packages/core-data", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/api-fetch": "file:packages/api-fetch", "@wordpress/blocks": "file:packages/blocks", "@wordpress/data": "file:packages/data", + "@wordpress/data-controls": "file:packages/data-controls", "@wordpress/deprecated": "file:packages/deprecated", "@wordpress/element": "file:packages/element", "@wordpress/i18n": "file:packages/i18n", @@ -10309,11 +10226,11 @@ "version": "file:packages/create-block", "dev": true, "requires": { - "chalk": "^2.4.2", + "chalk": "^4.0.0", "check-node-version": "^3.1.1", "commander": "^4.1.0", "execa": "^4.0.0", - "inquirer": "^7.0.3", + "inquirer": "^7.1.0", "lodash": "^4.17.15", "make-dir": "^3.0.0", "mustache": "^4.0.0", @@ -10330,7 +10247,7 @@ "@wordpress/data": { "version": "file:packages/data", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/compose": "file:packages/compose", "@wordpress/deprecated": "file:packages/deprecated", "@wordpress/element": "file:packages/element", @@ -10340,7 +10257,7 @@ "equivalent-key-map": "^0.2.2", "is-promise": "^2.1.0", "lodash": "^4.17.15", - "memize": "^1.0.5", + "memize": "^1.1.0", "redux": "^4.0.0", "turbo-combine-reducers": "^1.0.2", "use-memo-one": "^1.1.1" @@ -10356,7 +10273,7 @@ "@wordpress/date": { "version": "file:packages/date", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "moment": "^2.22.1", "moment-timezone": "^0.5.16" } @@ -10372,7 +10289,7 @@ "@wordpress/deprecated": { "version": "file:packages/deprecated", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/hooks": "file:packages/hooks" } }, @@ -10393,21 +10310,21 @@ "@wordpress/dom": { "version": "file:packages/dom", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "lodash": "^4.17.15" } }, "@wordpress/dom-ready": { "version": "file:packages/dom-ready", "requires": { - "@babel/runtime": "^7.8.3" + "@babel/runtime": "^7.9.2" } }, "@wordpress/e2e-test-utils": { "version": "file:packages/e2e-test-utils", "dev": true, "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/keycodes": "file:packages/keycodes", "@wordpress/url": "file:packages/url", "lodash": "^4.17.15", @@ -10435,15 +10352,39 @@ "@wordpress/jest-puppeteer-axe": "file:packages/jest-puppeteer-axe", "@wordpress/scripts": "file:packages/scripts", "@wordpress/url": "file:packages/url", - "expect-puppeteer": "^4.3.0", + "chalk": "^4.0.0", + "expect-puppeteer": "^4.4.0", "lodash": "^4.17.15", - "uuid": "^3.3.2" + "uuid": "^7.0.2" + } + }, + "@wordpress/edit-navigation": { + "version": "file:packages/edit-navigation", + "requires": { + "@babel/runtime": "^7.9.2", + "@wordpress/block-editor": "file:packages/block-editor", + "@wordpress/block-library": "file:packages/block-library", + "@wordpress/blocks": "file:packages/blocks", + "@wordpress/components": "file:packages/components", + "@wordpress/compose": "file:packages/compose", + "@wordpress/data": "file:packages/data", + "@wordpress/data-controls": "file:packages/data-controls", + "@wordpress/dom-ready": "file:packages/dom-ready", + "@wordpress/element": "file:packages/element", + "@wordpress/hooks": "file:packages/hooks", + "@wordpress/i18n": "file:packages/i18n", + "@wordpress/keyboard-shortcuts": "file:packages/keyboard-shortcuts", + "@wordpress/media-utils": "file:packages/media-utils", + "@wordpress/notices": "file:packages/notices", + "classnames": "^2.2.5", + "lodash": "^4.17.15", + "rememo": "^3.0.0" } }, "@wordpress/edit-post": { "version": "file:packages/edit-post", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/a11y": "file:packages/a11y", "@wordpress/api-fetch": "file:packages/api-fetch", "@wordpress/block-editor": "file:packages/block-editor", @@ -10453,11 +10394,13 @@ "@wordpress/compose": "file:packages/compose", "@wordpress/core-data": "file:packages/core-data", "@wordpress/data": "file:packages/data", + "@wordpress/data-controls": "file:packages/data-controls", "@wordpress/editor": "file:packages/editor", "@wordpress/element": "file:packages/element", "@wordpress/hooks": "file:packages/hooks", "@wordpress/i18n": "file:packages/i18n", "@wordpress/icons": "file:packages/icons", + "@wordpress/interface": "file:packages/interface", "@wordpress/keyboard-shortcuts": "file:packages/keyboard-shortcuts", "@wordpress/keycodes": "file:packages/keycodes", "@wordpress/media-utils": "file:packages/media-utils", @@ -10468,7 +10411,7 @@ "@wordpress/viewport": "file:packages/viewport", "classnames": "^2.2.5", "lodash": "^4.17.15", - "memize": "^1.0.5", + "memize": "^1.1.0", "refx": "^3.0.0", "rememo": "^3.0.0" } @@ -10476,7 +10419,7 @@ "@wordpress/edit-site": { "version": "file:packages/edit-site", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/block-editor": "file:packages/block-editor", "@wordpress/block-library": "file:packages/block-library", "@wordpress/blocks": "file:packages/blocks", @@ -10489,8 +10432,11 @@ "@wordpress/hooks": "file:packages/hooks", "@wordpress/i18n": "file:packages/i18n", "@wordpress/icons": "file:packages/icons", + "@wordpress/interface": "file:packages/interface", "@wordpress/media-utils": "file:packages/media-utils", "@wordpress/notices": "file:packages/notices", + "@wordpress/plugins": "file:packages/plugins", + "@wordpress/primitives": "file:packages/primitives", "@wordpress/url": "file:packages/url", "file-saver": "^2.0.2", "jszip": "^3.2.2", @@ -10500,7 +10446,7 @@ "@wordpress/edit-widgets": { "version": "file:packages/edit-widgets", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/block-editor": "file:packages/block-editor", "@wordpress/block-library": "file:packages/block-library", "@wordpress/blocks": "file:packages/blocks", @@ -10511,6 +10457,7 @@ "@wordpress/element": "file:packages/element", "@wordpress/hooks": "file:packages/hooks", "@wordpress/i18n": "file:packages/i18n", + "@wordpress/interface": "file:packages/interface", "@wordpress/media-utils": "file:packages/media-utils", "@wordpress/notices": "file:packages/notices", "lodash": "^4.17.15", @@ -10520,7 +10467,7 @@ "@wordpress/editor": { "version": "file:packages/editor", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/api-fetch": "file:packages/api-fetch", "@wordpress/autop": "file:packages/autop", "@wordpress/blob": "file:packages/blob", @@ -10551,7 +10498,7 @@ "@wordpress/wordcount": "file:packages/wordcount", "classnames": "^2.2.5", "lodash": "^4.17.15", - "memize": "^1.0.5", + "memize": "^1.1.0", "react-autosize-textarea": "^3.0.2", "redux-optimist": "^1.0.0", "refx": "^3.0.0", @@ -10561,7 +10508,7 @@ "@wordpress/element": { "version": "file:packages/element", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/escape-html": "file:packages/escape-html", "lodash": "^4.17.15", "react": "^16.9.0", @@ -10572,268 +10519,38 @@ "version": "file:packages/env", "dev": true, "requires": { - "chalk": "^2.4.2", + "chalk": "^4.0.0", "copy-dir": "^1.2.0", "docker-compose": "^0.22.2", "extract-zip": "^1.6.7", - "inquirer": "^7.0.4", + "got": "^10.7.0", + "inquirer": "^7.1.0", "js-yaml": "^3.13.1", "nodegit": "^0.26.2", "ora": "^4.0.2", - "request": "^2.88.2", - "request-progress": "^3.0.0", "rimraf": "^3.0.2", "terminal-link": "^2.0.0", "yargs": "^14.0.0" - }, - "dependencies": { - "ansi-escapes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.0.tgz", - "integrity": "sha512-EiYhwo0v255HUL6eDyuLrXEkTi7WwVCLAw+SeOQ7M7qdun1z1pum4DEm/nuqIVbPvi9RPPc9k9LbyBv6H0DwVg==", - "dev": true, - "requires": { - "type-fest": "^0.8.1" - } - }, - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "requires": { - "restore-cursor": "^3.1.0" - } - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "inquirer": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.4.tgz", - "integrity": "sha512-Bu5Td5+j11sCkqfqmUTiwv+tWisMtP0L7Q8WrqA2C/BbBhy1YTdFrvjjlrKq8oagA/tLQBski2Gcx/Sqyi2qSQ==", - "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "chalk": "^2.4.2", - "cli-cursor": "^3.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.15", - "mute-stream": "0.0.8", - "run-async": "^2.2.0", - "rxjs": "^6.5.3", - "string-width": "^4.1.0", - "strip-ansi": "^5.1.0", - "through": "^2.3.6" - } - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "mime-db": { - "version": "1.43.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", - "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==", - "dev": true - }, - "mime-types": { - "version": "2.1.26", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", - "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", - "dev": true, - "requires": { - "mime-db": "1.43.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, - "onetime": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", - "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "dev": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - } - }, - "restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "requires": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - } - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "rxjs": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz", - "integrity": "sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, - "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - } - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - } - } - }, - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - }, - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true - } } }, "@wordpress/escape-html": { "version": "file:packages/escape-html", "requires": { - "@babel/runtime": "^7.8.3" + "@babel/runtime": "^7.9.2" } }, "@wordpress/eslint-plugin": { "version": "file:packages/eslint-plugin", "requires": { - "babel-eslint": "^10.0.3", - "eslint-config-prettier": "^6.10.0", - "eslint-plugin-jest": "^22.15.1", - "eslint-plugin-jsdoc": "^15.8.0", + "@wordpress/prettier-config": "file:packages/prettier-config", + "babel-eslint": "^10.1.0", + "eslint-config-prettier": "^6.10.1", + "eslint-plugin-jest": "^23.8.2", + "eslint-plugin-jsdoc": "^22.1.0", "eslint-plugin-jsx-a11y": "^6.2.3", "eslint-plugin-prettier": "^3.1.2", - "eslint-plugin-react": "^7.14.3", - "eslint-plugin-react-hooks": "^1.6.1", - "eslint-plugin-react-native": "^3.8.1", + "eslint-plugin-react": "^7.19.0", + "eslint-plugin-react-hooks": "^3.0.0", "globals": "^12.0.0", "prettier": "npm:wp-prettier@1.19.1", "requireindex": "^1.2.0" @@ -10842,7 +10559,7 @@ "@wordpress/format-library": { "version": "file:packages/format-library", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/block-editor": "file:packages/block-editor", "@wordpress/components": "file:packages/components", "@wordpress/data": "file:packages/data", @@ -10860,71 +10577,359 @@ "@wordpress/hooks": { "version": "file:packages/hooks", "requires": { - "@babel/runtime": "^7.8.3" + "@babel/runtime": "^7.9.2" } }, "@wordpress/html-entities": { "version": "file:packages/html-entities", "requires": { - "@babel/runtime": "^7.8.3" + "@babel/runtime": "^7.9.2" } }, "@wordpress/i18n": { "version": "file:packages/i18n", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "gettext-parser": "^1.3.1", "lodash": "^4.17.15", - "memize": "^1.0.5", + "memize": "^1.1.0", "sprintf-js": "^1.1.1", - "tannin": "^1.1.0" + "tannin": "^1.2.0" } }, "@wordpress/icons": { "version": "file:packages/icons", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/element": "file:packages/element", "@wordpress/primitives": "file:packages/primitives" } }, + "@wordpress/interface": { + "version": "file:packages/interface", + "requires": { + "@babel/runtime": "^7.9.2", + "@wordpress/components": "file:packages/components", + "@wordpress/data": "file:packages/data", + "@wordpress/element": "file:packages/element", + "@wordpress/i18n": "file:packages/i18n", + "@wordpress/icons": "file:packages/icons", + "@wordpress/plugins": "file:packages/plugins", + "classnames": "^2.2.5", + "lodash": "^4.17.15" + } + }, "@wordpress/is-shallow-equal": { "version": "file:packages/is-shallow-equal", "requires": { - "@babel/runtime": "^7.8.3" + "@babel/runtime": "^7.9.2" } }, "@wordpress/jest-console": { "version": "file:packages/jest-console", "requires": { - "@babel/runtime": "^7.8.3", - "jest-matcher-utils": "^24.7.0", + "@babel/runtime": "^7.9.2", + "jest-matcher-utils": "^25.3.0", "lodash": "^4.17.15" } }, "@wordpress/jest-preset-default": { "version": "file:packages/jest-preset-default", "requires": { - "@jest/reporters": "^24.8.0", + "@jest/reporters": "^25.3.0", "@wordpress/jest-console": "file:packages/jest-console", - "babel-jest": "^24.9.0", - "enzyme": "^3.9.0", - "enzyme-adapter-react-16": "^1.10.0", - "enzyme-to-json": "^3.3.5" + "babel-jest": "^25.3.0", + "enzyme": "^3.11.0", + "enzyme-adapter-react-16": "^1.15.2", + "enzyme-to-json": "^3.4.4" + }, + "dependencies": { + "@jest/transform": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-25.4.0.tgz", + "integrity": "sha512-t1w2S6V1sk++1HHsxboWxPEuSpN8pxEvNrZN+Ud/knkROWtf8LeUmz73A4ezE8476a5AM00IZr9a8FO9x1+j3g==", + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^25.4.0", + "babel-plugin-istanbul": "^6.0.0", + "chalk": "^3.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.3", + "jest-haste-map": "^25.4.0", + "jest-regex-util": "^25.2.6", + "jest-util": "^25.4.0", + "micromatch": "^4.0.2", + "pirates": "^4.0.1", + "realpath-native": "^2.0.0", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + } + }, + "@jest/types": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz", + "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^15.0.0", + "chalk": "^3.0.0" + } + }, + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "babel-jest": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-25.4.0.tgz", + "integrity": "sha512-p+epx4K0ypmHuCnd8BapfyOwWwosNCYhedetQey1awddtfmEX0MmdxctGl956uwUmjwXR5VSS5xJcGX9DvdIog==", + "requires": { + "@jest/transform": "^25.4.0", + "@jest/types": "^25.4.0", + "@types/babel__core": "^7.1.7", + "babel-plugin-istanbul": "^6.0.0", + "babel-preset-jest": "^25.4.0", + "chalk": "^3.0.0", + "slash": "^3.0.0" + } + }, + "babel-plugin-istanbul": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", + "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^4.0.0", + "test-exclude": "^6.0.0" + } + }, + "babel-plugin-jest-hoist": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-25.4.0.tgz", + "integrity": "sha512-M3a10JCtTyKevb0MjuH6tU+cP/NVQZ82QPADqI1RQYY1OphztsCeIeQmTsHmF/NS6m0E51Zl4QNsI3odXSQF5w==", + "requires": { + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-preset-jest": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-25.4.0.tgz", + "integrity": "sha512-PwFiEWflHdu3JCeTr0Pb9NcHHE34qWFnPQRVPvqQITx4CsDCzs6o05923I10XvLvn9nNsRHuiVgB72wG/90ZHQ==", + "requires": { + "babel-plugin-jest-hoist": "^25.4.0", + "babel-preset-current-node-syntax": "^0.1.2" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "optional": true + }, + "graceful-fs": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "jest-haste-map": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-25.4.0.tgz", + "integrity": "sha512-5EoCe1gXfGC7jmXbKzqxESrgRcaO3SzWXGCnvp9BcT0CFMyrB1Q6LIsjl9RmvmJGQgW297TCfrdgiy574Rl9HQ==", + "requires": { + "@jest/types": "^25.4.0", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.1.2", + "graceful-fs": "^4.2.3", + "jest-serializer": "^25.2.6", + "jest-util": "^25.4.0", + "jest-worker": "^25.4.0", + "micromatch": "^4.0.2", + "sane": "^4.0.3", + "walker": "^1.0.7", + "which": "^2.0.2" + } + }, + "jest-regex-util": { + "version": "25.2.6", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-25.2.6.tgz", + "integrity": "sha512-KQqf7a0NrtCkYmZZzodPftn7fL1cq3GQAFVMn5Hg8uKx/fIenLEobNanUxb7abQ1sjADHBseG/2FGpsv/wr+Qw==" + }, + "jest-serializer": { + "version": "25.2.6", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-25.2.6.tgz", + "integrity": "sha512-RMVCfZsezQS2Ww4kB5HJTMaMJ0asmC0BHlnobQC6yEtxiFKIxohFA4QSXSabKwSggaNkqxn6Z2VwdFCjhUWuiQ==" + }, + "jest-util": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-25.4.0.tgz", + "integrity": "sha512-WSZD59sBtAUjLv1hMeKbNZXmMcrLRWcYqpO8Dz8b4CeCTZpfNQw2q9uwrYAD+BbJoLJlu4ezVPwtAmM/9/SlZA==", + "requires": { + "@jest/types": "^25.4.0", + "chalk": "^3.0.0", + "is-ci": "^2.0.0", + "make-dir": "^3.0.0" + } + }, + "jest-worker": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-25.4.0.tgz", + "integrity": "sha512-ghAs/1FtfYpMmYQ0AHqxV62XPvKdUDIBBApMZfly+E9JEmYh2K45G0R5dWxx986RN12pRCxsViwQVtGl+N4whw==", + "requires": { + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "realpath-native": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-2.0.0.tgz", + "integrity": "sha512-v1SEYUOXXdbBZK8ZuNgO4TBjamPsiSgcFr0aP+tEKpQZK8vooEUqV6nm6Cv502mX4NF2EfsnVqtNAHG+/6Ur1Q==" + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + } } }, "@wordpress/jest-puppeteer-axe": { "version": "file:packages/jest-puppeteer-axe", "dev": true, "requires": { - "@babel/runtime": "^7.8.3", - "axe-puppeteer": "^1.0.0" + "@babel/runtime": "^7.9.2", + "axe-puppeteer": "^1.1.0" } }, "@wordpress/keyboard-shortcuts": { "version": "file:packages/keyboard-shortcuts", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/compose": "file:packages/compose", "@wordpress/data": "file:packages/data", "@wordpress/element": "file:packages/element", @@ -10936,7 +10941,7 @@ "@wordpress/keycodes": { "version": "file:packages/keycodes", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/i18n": "file:packages/i18n", "lodash": "^4.17.15" } @@ -10952,7 +10957,7 @@ "@wordpress/list-reusable-blocks": { "version": "file:packages/list-reusable-blocks", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/api-fetch": "file:packages/api-fetch", "@wordpress/components": "file:packages/components", "@wordpress/compose": "file:packages/compose", @@ -10964,7 +10969,7 @@ "@wordpress/media-utils": { "version": "file:packages/media-utils", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/api-fetch": "file:packages/api-fetch", "@wordpress/blob": "file:packages/blob", "@wordpress/element": "file:packages/element", @@ -10975,7 +10980,7 @@ "@wordpress/notices": { "version": "file:packages/notices", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/a11y": "file:packages/a11y", "@wordpress/data": "file:packages/data", "lodash": "^4.17.15" @@ -10987,7 +10992,7 @@ "@wordpress/nux": { "version": "file:packages/nux", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/components": "file:packages/components", "@wordpress/compose": "file:packages/compose", "@wordpress/data": "file:packages/data", @@ -11002,7 +11007,7 @@ "@wordpress/plugins": { "version": "file:packages/plugins", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/compose": "file:packages/compose", "@wordpress/element": "file:packages/element", "@wordpress/hooks": "file:packages/hooks", @@ -11025,7 +11030,7 @@ "@wordpress/primitives": { "version": "file:packages/primitives", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/element": "file:packages/element", "classnames": "^2.2.5" } @@ -11033,7 +11038,16 @@ "@wordpress/priority-queue": { "version": "file:packages/priority-queue", "requires": { - "@babel/runtime": "^7.8.3" + "@babel/runtime": "^7.9.2" + } + }, + "@wordpress/project-management-automation": { + "version": "file:packages/project-management-automation", + "dev": true, + "requires": { + "@actions/core": "^1.0.0", + "@actions/github": "^1.0.0", + "@babel/runtime": "^7.9.2" } }, "@wordpress/react-native-aztec": { @@ -11044,137 +11058,1750 @@ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.0.tgz", "integrity": "sha1-zq8IMCL8RrSjX2nhPvda7Q1jmFY=", "requires": { - "fbjs": "^0.8.16", - "loose-envify": "^1.3.1", - "object-assign": "^4.1.1" + "fbjs": "^0.8.16", + "loose-envify": "^1.3.1", + "object-assign": "^4.1.1" + } + } + } + }, + "@wordpress/react-native-bridge": { + "version": "file:packages/react-native-bridge", + "requires": { + "@wordpress/react-native-aztec": "file:packages/react-native-aztec" + } + }, + "@wordpress/react-native-editor": { + "version": "file:packages/react-native-editor", + "requires": { + "@babel/runtime": "^7.7.7", + "@react-native-community/slider": "git+https://github.com/wordpress-mobile/react-native-slider.git#5ad284d92b8d886e366445bf215be741ed53ddc6", + "@wordpress/components": "file:packages/components", + "@wordpress/data": "file:packages/data", + "@wordpress/edit-post": "file:packages/edit-post", + "@wordpress/element": "file:packages/element", + "@wordpress/i18n": "file:packages/i18n", + "@wordpress/react-native-aztec": "file:packages/react-native-aztec", + "@wordpress/react-native-bridge": "file:packages/react-native-bridge", + "@wordpress/scripts": "file:packages/scripts", + "fast-average-color": "^4.3.0", + "jed": "^1.1.1", + "jsc-android": "^241213.1.0", + "jsdom-jscore-rn": "git+https://github.com/iamcco/jsdom-jscore-rn.git#a562f3d57c27c13e5bfc8cf82d496e69a3ba2800", + "metro-react-native-babel-preset": "0.57.0", + "metro-react-native-babel-transformer": "0.56.0", + "node-fetch": "^2.3.0", + "node-libs-react-native": "^1.0.2", + "patch-package": "^6.2.0", + "postinstall-prepare": "^1.0.1", + "react-native": "0.61.5", + "react-native-dark-mode": "git+https://github.com/wordpress-mobile/react-native-dark-mode.git#f09bf1480e7b34536413ab3300f29e4375edb2c6", + "react-native-get-random-values": "^1.4.0", + "react-native-hr": "git+https://github.com/Riglerr/react-native-hr.git#2d01a5cf77212d100e8b99e0310cce5234f977b3", + "react-native-keyboard-aware-scroll-view": "git+https://github.com/wordpress-mobile/react-native-keyboard-aware-scroll-view.git#gb-v0.8.8", + "react-native-linear-gradient": "git+https://github.com/wordpress-mobile/react-native-linear-gradient.git#52bf43077171cff8714ce3e0155f3ebb7f55bc37", + "react-native-modal": "^6.5.0", + "react-native-safe-area": "^0.5.0", + "react-native-sass-transformer": "^1.1.1", + "react-native-svg": "git+https://github.com/wordpress-mobile/react-native-svg.git#a628e92990a2404e30a0086f168bd2b5b7b4ce96", + "react-native-url-polyfill": "^1.1.2", + "react-native-video": "git+https://github.com/wordpress-mobile/react-native-video.git#6cdaddd9c81ebe2da5b28412d389cc105e156948", + "wd": "^1.11.1" + }, + "dependencies": { + "jsc-android": { + "version": "241213.1.0", + "resolved": "https://registry.npmjs.org/jsc-android/-/jsc-android-241213.1.0.tgz", + "integrity": "sha512-AH8NYyMNLNhcUEF97QbMxPNLNW+oiSBlvm1rsMNzgJ1d5TQzdh/AOJGsxeeESp3m9YIWGLCgUvGTVoVLs0p68A==" + } + } + }, + "@wordpress/redux-routine": { + "version": "file:packages/redux-routine", + "requires": { + "@babel/runtime": "^7.9.2", + "is-promise": "^2.1.0", + "lodash": "^4.17.15", + "rungen": "^0.3.2" + } + }, + "@wordpress/rich-text": { + "version": "file:packages/rich-text", + "requires": { + "@babel/runtime": "^7.9.2", + "@wordpress/compose": "file:packages/compose", + "@wordpress/data": "file:packages/data", + "@wordpress/deprecated": "file:packages/deprecated", + "@wordpress/element": "file:packages/element", + "@wordpress/escape-html": "file:packages/escape-html", + "@wordpress/is-shallow-equal": "file:packages/is-shallow-equal", + "@wordpress/keycodes": "file:packages/keycodes", + "classnames": "^2.2.5", + "lodash": "^4.17.15", + "memize": "^1.1.0", + "rememo": "^3.0.0" + } + }, + "@wordpress/scripts": { + "version": "file:packages/scripts", + "requires": { + "@svgr/webpack": "^5.2.0", + "@wordpress/babel-preset-default": "file:packages/babel-preset-default", + "@wordpress/dependency-extraction-webpack-plugin": "file:packages/dependency-extraction-webpack-plugin", + "@wordpress/eslint-plugin": "file:packages/eslint-plugin", + "@wordpress/jest-preset-default": "file:packages/jest-preset-default", + "@wordpress/npm-package-json-lint-config": "file:packages/npm-package-json-lint-config", + "@wordpress/prettier-config": "file:packages/prettier-config", + "babel-jest": "^25.3.0", + "babel-loader": "^8.1.0", + "chalk": "^4.0.0", + "check-node-version": "^3.1.1", + "command-exists": "^1.2.8", + "cross-spawn": "^5.1.0", + "decompress-zip": "^0.2.2", + "dir-glob": "^3.0.1", + "eslint": "^6.8.0", + "eslint-plugin-markdown": "^1.0.2", + "got": "^10.7.0", + "jest": "^25.3.0", + "jest-puppeteer": "^4.4.0", + "js-yaml": "^3.13.1", + "lodash": "^4.17.15", + "markdownlint": "^0.18.0", + "markdownlint-cli": "^0.21.0", + "minimist": "^1.2.0", + "npm-package-json-lint": "^5.0.0", + "prettier": "npm:wp-prettier@1.19.1", + "puppeteer": "npm:puppeteer-core@3.0.0", + "read-pkg-up": "^1.0.1", + "resolve-bin": "^0.4.0", + "source-map-loader": "^0.2.4", + "sprintf-js": "^1.1.1", + "stylelint": "^9.10.1", + "stylelint-config-wordpress": "^13.1.0", + "thread-loader": "^2.1.3", + "url-loader": "^3.0.0", + "webpack": "^4.42.0", + "webpack-bundle-analyzer": "^3.6.1", + "webpack-cli": "^3.3.11", + "webpack-livereload-plugin": "^2.3.0" + }, + "dependencies": { + "@jest/console": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-25.4.0.tgz", + "integrity": "sha512-CfE0erx4hdJ6t7RzAcE1wLG6ZzsHSmybvIBQDoCkDM1QaSeWL9wJMzID/2BbHHa7ll9SsbbK43HjbERbBaFX2A==", + "requires": { + "@jest/types": "^25.4.0", + "chalk": "^3.0.0", + "jest-message-util": "^25.4.0", + "jest-util": "^25.4.0", + "slash": "^3.0.0" + }, + "dependencies": { + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "@jest/core": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-25.4.0.tgz", + "integrity": "sha512-h1x9WSVV0+TKVtATGjyQIMJENs8aF6eUjnCoi4jyRemYZmekLr8EJOGQqTWEX8W6SbZ6Skesy9pGXrKeAolUJw==", + "requires": { + "@jest/console": "^25.4.0", + "@jest/reporters": "^25.4.0", + "@jest/test-result": "^25.4.0", + "@jest/transform": "^25.4.0", + "@jest/types": "^25.4.0", + "ansi-escapes": "^4.2.1", + "chalk": "^3.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.3", + "jest-changed-files": "^25.4.0", + "jest-config": "^25.4.0", + "jest-haste-map": "^25.4.0", + "jest-message-util": "^25.4.0", + "jest-regex-util": "^25.2.6", + "jest-resolve": "^25.4.0", + "jest-resolve-dependencies": "^25.4.0", + "jest-runner": "^25.4.0", + "jest-runtime": "^25.4.0", + "jest-snapshot": "^25.4.0", + "jest-util": "^25.4.0", + "jest-validate": "^25.4.0", + "jest-watcher": "^25.4.0", + "micromatch": "^4.0.2", + "p-each-series": "^2.1.0", + "realpath-native": "^2.0.0", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "@jest/environment": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-25.4.0.tgz", + "integrity": "sha512-KDctiak4mu7b4J6BIoN/+LUL3pscBzoUCP+EtSPd2tK9fqyDY5OF+CmkBywkFWezS9tyH5ACOQNtpjtueEDH6Q==", + "requires": { + "@jest/fake-timers": "^25.4.0", + "@jest/types": "^25.4.0", + "jest-mock": "^25.4.0" + } + }, + "@jest/fake-timers": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-25.4.0.tgz", + "integrity": "sha512-lI9z+VOmVX4dPPFzyj0vm+UtaB8dCJJ852lcDnY0uCPRvZAaVGnMwBBc1wxtf+h7Vz6KszoOvKAt4QijDnHDkg==", + "requires": { + "@jest/types": "^25.4.0", + "jest-message-util": "^25.4.0", + "jest-mock": "^25.4.0", + "jest-util": "^25.4.0", + "lolex": "^5.0.0" + } + }, + "@jest/reporters": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-25.4.0.tgz", + "integrity": "sha512-bhx/buYbZgLZm4JWLcRJ/q9Gvmd3oUh7k2V7gA4ZYBx6J28pIuykIouclRdiAC6eGVX1uRZT+GK4CQJLd/PwPg==", + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^25.4.0", + "@jest/test-result": "^25.4.0", + "@jest/transform": "^25.4.0", + "@jest/types": "^25.4.0", + "chalk": "^3.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^4.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "jest-haste-map": "^25.4.0", + "jest-resolve": "^25.4.0", + "jest-util": "^25.4.0", + "jest-worker": "^25.4.0", + "node-notifier": "^6.0.0", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^3.1.0", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^4.1.3" + }, + "dependencies": { + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "@jest/source-map": { + "version": "25.2.6", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-25.2.6.tgz", + "integrity": "sha512-VuIRZF8M2zxYFGTEhkNSvQkUKafQro4y+mwUxy5ewRqs5N/ynSFUODYp3fy1zCnbCMy1pz3k+u57uCqx8QRSQQ==", + "requires": { + "callsites": "^3.0.0", + "graceful-fs": "^4.2.3", + "source-map": "^0.6.0" + } + }, + "@jest/test-result": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-25.4.0.tgz", + "integrity": "sha512-8BAKPaMCHlL941eyfqhWbmp3MebtzywlxzV+qtngQ3FH+RBqnoSAhNEPj4MG7d2NVUrMOVfrwuzGpVIK+QnMAA==", + "requires": { + "@jest/console": "^25.4.0", + "@jest/types": "^25.4.0", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + } + }, + "@jest/test-sequencer": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-25.4.0.tgz", + "integrity": "sha512-240cI+nsM3attx2bMp9uGjjHrwrpvxxrZi8Tyqp/cfOzl98oZXVakXBgxODGyBYAy/UGXPKXLvNc2GaqItrsJg==", + "requires": { + "@jest/test-result": "^25.4.0", + "jest-haste-map": "^25.4.0", + "jest-runner": "^25.4.0", + "jest-runtime": "^25.4.0" + } + }, + "@jest/transform": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-25.4.0.tgz", + "integrity": "sha512-t1w2S6V1sk++1HHsxboWxPEuSpN8pxEvNrZN+Ud/knkROWtf8LeUmz73A4ezE8476a5AM00IZr9a8FO9x1+j3g==", + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^25.4.0", + "babel-plugin-istanbul": "^6.0.0", + "chalk": "^3.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.3", + "jest-haste-map": "^25.4.0", + "jest-regex-util": "^25.2.6", + "jest-util": "^25.4.0", + "micromatch": "^4.0.2", + "pirates": "^4.0.1", + "realpath-native": "^2.0.0", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + }, + "dependencies": { + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "@jest/types": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz", + "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^15.0.0", + "chalk": "^3.0.0" + }, + "dependencies": { + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "agent-base": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz", + "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==" + }, + "ansi-escapes": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", + "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "requires": { + "type-fest": "^0.11.0" + }, + "dependencies": { + "type-fest": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", + "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==" + } + } + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + }, + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "babel-jest": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-25.4.0.tgz", + "integrity": "sha512-p+epx4K0ypmHuCnd8BapfyOwWwosNCYhedetQey1awddtfmEX0MmdxctGl956uwUmjwXR5VSS5xJcGX9DvdIog==", + "requires": { + "@jest/transform": "^25.4.0", + "@jest/types": "^25.4.0", + "@types/babel__core": "^7.1.7", + "babel-plugin-istanbul": "^6.0.0", + "babel-preset-jest": "^25.4.0", + "chalk": "^3.0.0", + "slash": "^3.0.0" + }, + "dependencies": { + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "babel-plugin-istanbul": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", + "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^4.0.0", + "test-exclude": "^6.0.0" + } + }, + "babel-plugin-jest-hoist": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-25.4.0.tgz", + "integrity": "sha512-M3a10JCtTyKevb0MjuH6tU+cP/NVQZ82QPADqI1RQYY1OphztsCeIeQmTsHmF/NS6m0E51Zl4QNsI3odXSQF5w==", + "requires": { + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-preset-jest": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-25.4.0.tgz", + "integrity": "sha512-PwFiEWflHdu3JCeTr0Pb9NcHHE34qWFnPQRVPvqQITx4CsDCzs6o05923I10XvLvn9nNsRHuiVgB72wG/90ZHQ==", + "requires": { + "babel-plugin-jest-hoist": "^25.4.0", + "babel-preset-current-node-syntax": "^0.1.2" + } + }, + "bl": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.2.tgz", + "integrity": "sha512-j4OH8f6Qg2bGuWfRiltT2HYGx0e1QcBTrK9KAHNMwMZdQnDZFk0ZSYIpADjYCB3U12nicC5tVJwSIhwOWjb4RQ==", + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + } + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" + }, + "detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==" + }, + "diff-sequences": { + "version": "25.2.6", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-25.2.6.tgz", + "integrity": "sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg==" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "execa": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-3.4.0.tgz", + "integrity": "sha512-r9vdGQk4bmCuK1yKQu1KTwcT2zwfWdbdaXfCtAh+5nU/4fSX+JAb7vZGvI5naJrQlvONrEB20jeruESI69530g==", + "requires": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "p-finally": "^2.0.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.2.tgz", + "integrity": "sha512-PD6G8QG3S4FK/XCGFbEQrDqO2AnMMsy0meR7lerlIOHAAbkuavGU/pOqprrlvfTNjvowivTeBsjebAL0NSoMxw==", + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + } + } + }, + "expect": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-25.4.0.tgz", + "integrity": "sha512-7BDIX99BTi12/sNGJXA9KMRcby4iAmu1xccBOhyKCyEhjcVKS3hPmHdA/4nSI9QGIOkUropKqr3vv7WMDM5lvQ==", + "requires": { + "@jest/types": "^25.4.0", + "ansi-styles": "^4.0.0", + "jest-get-type": "^25.2.6", + "jest-matcher-utils": "^25.4.0", + "jest-message-util": "^25.4.0", + "jest-regex-util": "^25.2.6" + } + }, + "extract-zip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.0.tgz", + "integrity": "sha512-i42GQ498yibjdvIhivUsRslx608whtGoFIhF26Z7O4MYncBxp8CwalOs1lnHy21A9sIohWO2+uiE4SRtC9JXDg==", + "requires": { + "@types/yauzl": "^2.9.1", + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + } + }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "requires": { + "pend": "~1.2.0" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "optional": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "get-stream": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", + "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "requires": { + "pump": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "https-proxy-agent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz", + "integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==", + "requires": { + "agent-base": "5", + "debug": "4" + } + }, + "import-local": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", + "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" + }, + "is-wsl": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.1.1.tgz", + "integrity": "sha512-umZHcSrwlDHo2TGMXv0DZ8dIUGunZ2Iv68YZnrmCiBPkZ4aaOhtv7pXJKeki9k3qJ3RJr0cDyitcl5wEH3AYog==", + "optional": true + }, + "istanbul-reports": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", + "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "jest": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-25.4.0.tgz", + "integrity": "sha512-XWipOheGB4wai5JfCYXd6vwsWNwM/dirjRoZgAa7H2wd8ODWbli2AiKjqG8AYhyx+8+5FBEdpO92VhGlBydzbw==", + "requires": { + "@jest/core": "^25.4.0", + "import-local": "^3.0.2", + "jest-cli": "^25.4.0" + }, + "dependencies": { + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "jest-cli": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-25.4.0.tgz", + "integrity": "sha512-usyrj1lzCJZMRN1r3QEdnn8e6E6yCx/QN7+B1sLoA68V7f3WlsxSSQfy0+BAwRiF4Hz2eHauf11GZG3PIfWTXQ==", + "requires": { + "@jest/core": "^25.4.0", + "@jest/test-result": "^25.4.0", + "@jest/types": "^25.4.0", + "chalk": "^3.0.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "is-ci": "^2.0.0", + "jest-config": "^25.4.0", + "jest-util": "^25.4.0", + "jest-validate": "^25.4.0", + "prompts": "^2.0.1", + "realpath-native": "^2.0.0", + "yargs": "^15.3.1" + } + } + } + }, + "jest-changed-files": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-25.4.0.tgz", + "integrity": "sha512-VR/rfJsEs4BVMkwOTuStRyS630fidFVekdw/lBaBQjx9KK3VZFOZ2c0fsom2fRp8pMCrCTP6LGna00o/DXGlqA==", + "requires": { + "@jest/types": "^25.4.0", + "execa": "^3.2.0", + "throat": "^5.0.0" + } + }, + "jest-config": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-25.4.0.tgz", + "integrity": "sha512-egT9aKYxMyMSQV1aqTgam0SkI5/I2P9qrKexN5r2uuM2+68ypnc+zPGmfUxK7p1UhE7dYH9SLBS7yb+TtmT1AA==", + "requires": { + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^25.4.0", + "@jest/types": "^25.4.0", + "babel-jest": "^25.4.0", + "chalk": "^3.0.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "jest-environment-jsdom": "^25.4.0", + "jest-environment-node": "^25.4.0", + "jest-get-type": "^25.2.6", + "jest-jasmine2": "^25.4.0", + "jest-regex-util": "^25.2.6", + "jest-resolve": "^25.4.0", + "jest-util": "^25.4.0", + "jest-validate": "^25.4.0", + "micromatch": "^4.0.2", + "pretty-format": "^25.4.0", + "realpath-native": "^2.0.0" + }, + "dependencies": { + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "jest-diff": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-25.4.0.tgz", + "integrity": "sha512-kklLbJVXW0y8UKOWOdYhI6TH5MG6QAxrWiBMgQaPIuhj3dNFGirKCd+/xfplBXICQ7fI+3QcqHm9p9lWu1N6ug==", + "requires": { + "chalk": "^3.0.0", + "diff-sequences": "^25.2.6", + "jest-get-type": "^25.2.6", + "pretty-format": "^25.4.0" + }, + "dependencies": { + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "jest-docblock": { + "version": "25.3.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-25.3.0.tgz", + "integrity": "sha512-aktF0kCar8+zxRHxQZwxMy70stc9R1mOmrLsT5VO3pIT0uzGRSDAXxSlz4NqQWpuLjPpuMhPRl7H+5FRsvIQAg==", + "requires": { + "detect-newline": "^3.0.0" + } + }, + "jest-each": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-25.4.0.tgz", + "integrity": "sha512-lwRIJ8/vQU/6vq3nnSSUw1Y3nz5tkYSFIywGCZpUBd6WcRgpn8NmJoQICojbpZmsJOJNHm0BKdyuJ6Xdx+eDQQ==", + "requires": { + "@jest/types": "^25.4.0", + "chalk": "^3.0.0", + "jest-get-type": "^25.2.6", + "jest-util": "^25.4.0", + "pretty-format": "^25.4.0" + }, + "dependencies": { + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "jest-environment-jsdom": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-25.4.0.tgz", + "integrity": "sha512-KTitVGMDrn2+pt7aZ8/yUTuS333w3pWt1Mf88vMntw7ZSBNDkRS6/4XLbFpWXYfWfp1FjcjQTOKzbK20oIehWQ==", + "requires": { + "@jest/environment": "^25.4.0", + "@jest/fake-timers": "^25.4.0", + "@jest/types": "^25.4.0", + "jest-mock": "^25.4.0", + "jest-util": "^25.4.0", + "jsdom": "^15.2.1" + } + }, + "jest-environment-node": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-25.4.0.tgz", + "integrity": "sha512-wryZ18vsxEAKFH7Z74zi/y/SyI1j6UkVZ6QsllBuT/bWlahNfQjLNwFsgh/5u7O957dYFoXj4yfma4n4X6kU9A==", + "requires": { + "@jest/environment": "^25.4.0", + "@jest/fake-timers": "^25.4.0", + "@jest/types": "^25.4.0", + "jest-mock": "^25.4.0", + "jest-util": "^25.4.0", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "jest-get-type": { + "version": "25.2.6", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.2.6.tgz", + "integrity": "sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig==" + }, + "jest-haste-map": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-25.4.0.tgz", + "integrity": "sha512-5EoCe1gXfGC7jmXbKzqxESrgRcaO3SzWXGCnvp9BcT0CFMyrB1Q6LIsjl9RmvmJGQgW297TCfrdgiy574Rl9HQ==", + "requires": { + "@jest/types": "^25.4.0", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.1.2", + "graceful-fs": "^4.2.3", + "jest-serializer": "^25.2.6", + "jest-util": "^25.4.0", + "jest-worker": "^25.4.0", + "micromatch": "^4.0.2", + "sane": "^4.0.3", + "walker": "^1.0.7", + "which": "^2.0.2" + } + }, + "jest-jasmine2": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-25.4.0.tgz", + "integrity": "sha512-QccxnozujVKYNEhMQ1vREiz859fPN/XklOzfQjm2j9IGytAkUbSwjFRBtQbHaNZ88cItMpw02JnHGsIdfdpwxQ==", + "requires": { + "@babel/traverse": "^7.1.0", + "@jest/environment": "^25.4.0", + "@jest/source-map": "^25.2.6", + "@jest/test-result": "^25.4.0", + "@jest/types": "^25.4.0", + "chalk": "^3.0.0", + "co": "^4.6.0", + "expect": "^25.4.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^25.4.0", + "jest-matcher-utils": "^25.4.0", + "jest-message-util": "^25.4.0", + "jest-runtime": "^25.4.0", + "jest-snapshot": "^25.4.0", + "jest-util": "^25.4.0", + "pretty-format": "^25.4.0", + "throat": "^5.0.0" + }, + "dependencies": { + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "jest-leak-detector": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-25.4.0.tgz", + "integrity": "sha512-7Y6Bqfv2xWsB+7w44dvZuLs5SQ//fzhETgOGG7Gq3TTGFdYvAgXGwV8z159RFZ6fXiCPm/szQ90CyfVos9JIFQ==", + "requires": { + "jest-get-type": "^25.2.6", + "pretty-format": "^25.4.0" + } + }, + "jest-matcher-utils": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-25.4.0.tgz", + "integrity": "sha512-yPMdtj7YDgXhnGbc66bowk8AkQ0YwClbbwk3Kzhn5GVDrciiCr27U4NJRbrqXbTdtxjImONITg2LiRIw650k5A==", + "requires": { + "chalk": "^3.0.0", + "jest-diff": "^25.4.0", + "jest-get-type": "^25.2.6", + "pretty-format": "^25.4.0" + }, + "dependencies": { + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "jest-message-util": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-25.4.0.tgz", + "integrity": "sha512-LYY9hRcVGgMeMwmdfh9tTjeux1OjZHMusq/E5f3tJN+dAoVVkJtq5ZUEPIcB7bpxDUt2zjUsrwg0EGgPQ+OhXQ==", + "requires": { + "@babel/code-frame": "^7.0.0", + "@jest/types": "^25.4.0", + "@types/stack-utils": "^1.0.1", + "chalk": "^3.0.0", + "micromatch": "^4.0.2", + "slash": "^3.0.0", + "stack-utils": "^1.0.1" + }, + "dependencies": { + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "jest-mock": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-25.4.0.tgz", + "integrity": "sha512-MdazSfcYAUjJjuVTTnusLPzE0pE4VXpOUzWdj8sbM+q6abUjm3bATVPXFqTXrxSieR8ocpvQ9v/QaQCftioQFg==", + "requires": { + "@jest/types": "^25.4.0" + } + }, + "jest-regex-util": { + "version": "25.2.6", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-25.2.6.tgz", + "integrity": "sha512-KQqf7a0NrtCkYmZZzodPftn7fL1cq3GQAFVMn5Hg8uKx/fIenLEobNanUxb7abQ1sjADHBseG/2FGpsv/wr+Qw==" + }, + "jest-resolve": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-25.4.0.tgz", + "integrity": "sha512-wOsKqVDFWUiv8BtLMCC6uAJ/pHZkfFgoBTgPtmYlsprAjkxrr2U++ZnB3l5ykBMd2O24lXvf30SMAjJIW6k2aA==", + "requires": { + "@jest/types": "^25.4.0", + "browser-resolve": "^1.11.3", + "chalk": "^3.0.0", + "jest-pnp-resolver": "^1.2.1", + "read-pkg-up": "^7.0.1", + "realpath-native": "^2.0.0", + "resolve": "^1.15.1", + "slash": "^3.0.0" + }, + "dependencies": { + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + } + } + } + }, + "jest-resolve-dependencies": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-25.4.0.tgz", + "integrity": "sha512-A0eoZXx6kLiuG1Ui7wITQPl04HwjLErKIJTt8GR3c7UoDAtzW84JtCrgrJ6Tkw6c6MwHEyAaLk7dEPml5pf48A==", + "requires": { + "@jest/types": "^25.4.0", + "jest-regex-util": "^25.2.6", + "jest-snapshot": "^25.4.0" + } + }, + "jest-runner": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-25.4.0.tgz", + "integrity": "sha512-wWQSbVgj2e/1chFdMRKZdvlmA6p1IPujhpLT7TKNtCSl1B0PGBGvJjCaiBal/twaU2yfk8VKezHWexM8IliBfA==", + "requires": { + "@jest/console": "^25.4.0", + "@jest/environment": "^25.4.0", + "@jest/test-result": "^25.4.0", + "@jest/types": "^25.4.0", + "chalk": "^3.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.3", + "jest-config": "^25.4.0", + "jest-docblock": "^25.3.0", + "jest-haste-map": "^25.4.0", + "jest-jasmine2": "^25.4.0", + "jest-leak-detector": "^25.4.0", + "jest-message-util": "^25.4.0", + "jest-resolve": "^25.4.0", + "jest-runtime": "^25.4.0", + "jest-util": "^25.4.0", + "jest-worker": "^25.4.0", + "source-map-support": "^0.5.6", + "throat": "^5.0.0" + }, + "dependencies": { + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "jest-runtime": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-25.4.0.tgz", + "integrity": "sha512-lgNJlCDULtXu9FumnwCyWlOub8iytijwsPNa30BKrSNtgoT6NUMXOPrZvsH06U6v0wgD/Igwz13nKA2wEKU2VA==", + "requires": { + "@jest/console": "^25.4.0", + "@jest/environment": "^25.4.0", + "@jest/source-map": "^25.2.6", + "@jest/test-result": "^25.4.0", + "@jest/transform": "^25.4.0", + "@jest/types": "^25.4.0", + "@types/yargs": "^15.0.0", + "chalk": "^3.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.3", + "jest-config": "^25.4.0", + "jest-haste-map": "^25.4.0", + "jest-message-util": "^25.4.0", + "jest-mock": "^25.4.0", + "jest-regex-util": "^25.2.6", + "jest-resolve": "^25.4.0", + "jest-snapshot": "^25.4.0", + "jest-util": "^25.4.0", + "jest-validate": "^25.4.0", + "realpath-native": "^2.0.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0", + "yargs": "^15.3.1" + }, + "dependencies": { + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "jest-serializer": { + "version": "25.2.6", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-25.2.6.tgz", + "integrity": "sha512-RMVCfZsezQS2Ww4kB5HJTMaMJ0asmC0BHlnobQC6yEtxiFKIxohFA4QSXSabKwSggaNkqxn6Z2VwdFCjhUWuiQ==" + }, + "jest-snapshot": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-25.4.0.tgz", + "integrity": "sha512-J4CJ0X2SaGheYRZdLz9CRHn9jUknVmlks4UBeu270hPAvdsauFXOhx9SQP2JtRzhnR3cvro/9N9KP83/uvFfRg==", + "requires": { + "@babel/types": "^7.0.0", + "@jest/types": "^25.4.0", + "@types/prettier": "^1.19.0", + "chalk": "^3.0.0", + "expect": "^25.4.0", + "jest-diff": "^25.4.0", + "jest-get-type": "^25.2.6", + "jest-matcher-utils": "^25.4.0", + "jest-message-util": "^25.4.0", + "jest-resolve": "^25.4.0", + "make-dir": "^3.0.0", + "natural-compare": "^1.4.0", + "pretty-format": "^25.4.0", + "semver": "^6.3.0" + }, + "dependencies": { + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "jest-util": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-25.4.0.tgz", + "integrity": "sha512-WSZD59sBtAUjLv1hMeKbNZXmMcrLRWcYqpO8Dz8b4CeCTZpfNQw2q9uwrYAD+BbJoLJlu4ezVPwtAmM/9/SlZA==", + "requires": { + "@jest/types": "^25.4.0", + "chalk": "^3.0.0", + "is-ci": "^2.0.0", + "make-dir": "^3.0.0" + }, + "dependencies": { + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "jest-validate": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-25.4.0.tgz", + "integrity": "sha512-hvjmes/EFVJSoeP1yOl8qR8mAtMR3ToBkZeXrD/ZS9VxRyWDqQ/E1C5ucMTeSmEOGLipvdlyipiGbHJ+R1MQ0g==", + "requires": { + "@jest/types": "^25.4.0", + "camelcase": "^5.3.1", + "chalk": "^3.0.0", + "jest-get-type": "^25.2.6", + "leven": "^3.1.0", + "pretty-format": "^25.4.0" + }, + "dependencies": { + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "jest-watcher": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-25.4.0.tgz", + "integrity": "sha512-36IUfOSRELsKLB7k25j/wutx0aVuHFN6wO94gPNjQtQqFPa2rkOymmx9rM5EzbF3XBZZ2oqD9xbRVoYa2w86gw==", + "requires": { + "@jest/test-result": "^25.4.0", + "@jest/types": "^25.4.0", + "ansi-escapes": "^4.2.1", + "chalk": "^3.0.0", + "jest-util": "^25.4.0", + "string-length": "^3.1.0" + }, + "dependencies": { + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "jest-worker": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-25.4.0.tgz", + "integrity": "sha512-ghAs/1FtfYpMmYQ0AHqxV62XPvKdUDIBBApMZfly+E9JEmYh2K45G0R5dWxx986RN12pRCxsViwQVtGl+N4whw==", + "requires": { + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + } + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "requires": { + "p-locate": "^4.1.0" + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + } + }, + "mime-db": { + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", + "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==" + }, + "mime-types": { + "version": "2.1.26", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", + "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", + "requires": { + "mime-db": "1.43.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node-notifier": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-6.0.0.tgz", + "integrity": "sha512-SVfQ/wMw+DesunOm5cKqr6yDcvUTDl/yc97ybGHMrteNEY6oekXpNpS3lZwgLlwz0FLgHoiW28ZpmBHUDg37cw==", + "optional": true, + "requires": { + "growly": "^1.3.0", + "is-wsl": "^2.1.1", + "semver": "^6.3.0", + "shellwords": "^0.1.1", + "which": "^1.3.1" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "optional": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "optional": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "requires": { + "path-key": "^3.0.0" + } + }, + "onetime": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "p-each-series": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.1.0.tgz", + "integrity": "sha512-ZuRs1miPT4HrjFa+9fRfOFXxGJfORgelKV9f9nNOWw2gl6gVsRaVDOQP0+MI0G0wGKns1Yacsu0GjOFbTK0JFQ==" + }, + "p-finally": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz", + "integrity": "sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==" + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "parse-json": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", + "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1", + "lines-and-columns": "^1.1.6" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "requires": { + "find-up": "^4.0.0" + } + }, + "pretty-format": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.4.0.tgz", + "integrity": "sha512-PI/2dpGjXK5HyXexLPZU/jw5T9Q6S1YVXxxVxco+LIqzUFHXIbKZKdUVt7GcX7QUCr31+3fzhi4gN4/wUYPVxQ==", + "requires": { + "@jest/types": "^25.4.0", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^16.12.0" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "puppeteer": { + "version": "npm:puppeteer@3.0.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-3.0.0.tgz", + "integrity": "sha512-oWjZFGMc0q2ak+8OxdmMffS79LIT0UEtmpV4h1/AARvESIqqKljf8mrfP+dQ2kas7XttsAZIxRBuWu7Y5JH8KQ==", + "requires": { + "@types/mime-types": "^2.1.0", + "debug": "^4.1.0", + "extract-zip": "^2.0.0", + "https-proxy-agent": "^4.0.0", + "mime": "^2.0.3", + "mime-types": "^2.1.25", + "progress": "^2.0.1", + "proxy-from-env": "^1.0.0", + "rimraf": "^3.0.2", + "tar-fs": "^2.0.0", + "unbzip2-stream": "^1.3.3", + "ws": "^7.2.3" + } + }, + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==" + } + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "realpath-native": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-2.0.0.tgz", + "integrity": "sha512-v1SEYUOXXdbBZK8ZuNgO4TBjamPsiSgcFr0aP+tEKpQZK8vooEUqV6nm6Cv502mX4NF2EfsnVqtNAHG+/6Ur1Q==" + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, + "resolve": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.16.1.tgz", + "integrity": "sha512-rmAglCSqWWMrrBv/XM6sW0NuRFiKViw/W4d9EbC4pt+49H8JwHy+mcGmALTEg504AUDcLTvb1T2q3E9AnmY+ig==", + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "requires": { + "resolve-from": "^5.0.0" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==" + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "tar-fs": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.1.tgz", + "integrity": "sha512-6tzWDMeroL87uF/+lin46k+Q+46rAJ0SyPGz7OW7wTgblI273hsBqk2C1j0/xNadNLKDTUL9BukSjB7cwgmlPA==", + "requires": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.0.0" + } + }, + "tar-stream": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.2.tgz", + "integrity": "sha512-UaF6FoJ32WqALZGOIAApXx+OdxhekNMChu6axLJR85zMMjXKWFGjbIRe+J6P4UnRGg9rAwWvbTT0oI7hD/Un7Q==", + "requires": { + "bl": "^4.0.1", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + } + }, + "throat": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", + "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==" + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" + }, + "v8-to-istanbul": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-4.1.3.tgz", + "integrity": "sha512-sAjOC+Kki6aJVbUOXJbcR0MnbfjvBzwKZazEJymA2IX49uoOdEdk+4fBq5cXgYgiyKtAyrrJNtBZdOeDIF+Fng==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" + }, + "dependencies": { + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" + } + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "ws": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.3.tgz", + "integrity": "sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ==" + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" + }, + "yargs": { + "version": "15.3.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz", + "integrity": "sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==", + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.1" + } + }, + "yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" } } } }, - "@wordpress/react-native-bridge": { - "version": "file:packages/react-native-bridge", - "requires": { - "@wordpress/react-native-aztec": "file:packages/react-native-aztec" - } - }, - "@wordpress/react-native-editor": { - "version": "file:packages/react-native-editor", - "requires": { - "@babel/runtime": "^7.7.7", - "@react-native-community/slider": "git+https://github.com/wordpress-mobile/react-native-slider.git#5ad284d92b8d886e366445bf215be741ed53ddc6", - "@wordpress/data": "file:packages/data", - "@wordpress/edit-post": "file:packages/edit-post", - "@wordpress/element": "file:packages/element", - "@wordpress/i18n": "file:packages/i18n", - "@wordpress/react-native-aztec": "file:packages/react-native-aztec", - "@wordpress/react-native-bridge": "file:packages/react-native-bridge", - "@wordpress/scripts": "file:packages/scripts", - "fast-average-color": "^4.3.0", - "jed": "^1.1.1", - "jsc-android": "^241213.1.0", - "jsdom-jscore-rn": "git+https://github.com/iamcco/jsdom-jscore-rn.git#a562f3d57c27c13e5bfc8cf82d496e69a3ba2800", - "metro-react-native-babel-preset": "0.57.0", - "metro-react-native-babel-transformer": "0.56.0", - "node-fetch": "^2.3.0", - "node-libs-react-native": "^1.0.2", - "patch-package": "^6.2.0", - "postinstall-prepare": "^1.0.1", - "react-native": "0.61.5", - "react-native-dark-mode": "git+https://github.com/wordpress-mobile/react-native-dark-mode.git#f09bf1480e7b34536413ab3300f29e4375edb2c6", - "react-native-hr": "git+https://github.com/Riglerr/react-native-hr.git#2d01a5cf77212d100e8b99e0310cce5234f977b3", - "react-native-keyboard-aware-scroll-view": "git+https://github.com/wordpress-mobile/react-native-keyboard-aware-scroll-view.git#gb-v0.8.8", - "react-native-linear-gradient": "git+https://github.com/wordpress-mobile/react-native-linear-gradient.git#52bf43077171cff8714ce3e0155f3ebb7f55bc37", - "react-native-modal": "^6.5.0", - "react-native-safe-area": "^0.5.0", - "react-native-sass-transformer": "^1.1.1", - "react-native-svg": "git+https://github.com/wordpress-mobile/react-native-svg.git#a628e92990a2404e30a0086f168bd2b5b7b4ce96", - "react-native-url-polyfill": "^1.1.2", - "react-native-video": "git+https://github.com/wordpress-mobile/react-native-video.git#c43bdf6b06d361da399b98b8d2e32b578fa188ac", - "wd": "^1.11.1" - }, - "dependencies": { - "jsc-android": { - "version": "241213.1.0", - "resolved": "https://registry.npmjs.org/jsc-android/-/jsc-android-241213.1.0.tgz", - "integrity": "sha512-AH8NYyMNLNhcUEF97QbMxPNLNW+oiSBlvm1rsMNzgJ1d5TQzdh/AOJGsxeeESp3m9YIWGLCgUvGTVoVLs0p68A==" - } - } - }, - "@wordpress/redux-routine": { - "version": "file:packages/redux-routine", - "requires": { - "@babel/runtime": "^7.8.3", - "is-promise": "^2.1.0", - "lodash": "^4.17.15", - "rungen": "^0.3.2" - } - }, - "@wordpress/rich-text": { - "version": "file:packages/rich-text", - "requires": { - "@babel/runtime": "^7.8.3", - "@wordpress/compose": "file:packages/compose", - "@wordpress/data": "file:packages/data", - "@wordpress/deprecated": "file:packages/deprecated", - "@wordpress/element": "file:packages/element", - "@wordpress/escape-html": "file:packages/escape-html", - "@wordpress/is-shallow-equal": "file:packages/is-shallow-equal", - "@wordpress/keycodes": "file:packages/keycodes", - "classnames": "^2.2.5", - "lodash": "^4.17.15", - "memize": "^1.0.5", - "rememo": "^3.0.0" - } - }, - "@wordpress/scripts": { - "version": "file:packages/scripts", - "requires": { - "@svgr/webpack": "^5.2.0", - "@wordpress/babel-preset-default": "file:packages/babel-preset-default", - "@wordpress/dependency-extraction-webpack-plugin": "file:packages/dependency-extraction-webpack-plugin", - "@wordpress/eslint-plugin": "file:packages/eslint-plugin", - "@wordpress/jest-preset-default": "file:packages/jest-preset-default", - "@wordpress/npm-package-json-lint-config": "file:packages/npm-package-json-lint-config", - "@wordpress/prettier-config": "file:packages/prettier-config", - "babel-jest": "^24.9.0", - "babel-loader": "^8.0.6", - "chalk": "^2.4.2", - "check-node-version": "^3.1.1", - "command-exists": "^1.2.8", - "cross-spawn": "^5.1.0", - "decompress-zip": "^0.2.2", - "dir-glob": "^3.0.1", - "eslint": "^6.1.0", - "eslint-plugin-markdown": "1.0.1", - "jest": "^24.9.0", - "jest-puppeteer": "^4.3.0", - "js-yaml": "^3.13.1", - "lodash": "^4.17.15", - "markdownlint": "^0.18.0", - "markdownlint-cli": "^0.21.0", - "minimist": "^1.2.0", - "npm-package-json-lint": "^4.0.3", - "prettier": "npm:wp-prettier@1.19.1", - "puppeteer": "^2.0.0", - "read-pkg-up": "^1.0.1", - "request": "^2.88.0", - "resolve-bin": "^0.4.0", - "source-map-loader": "^0.2.4", - "sprintf-js": "^1.1.1", - "stylelint": "^9.10.1", - "stylelint-config-wordpress": "^13.1.0", - "thread-loader": "^2.1.3", - "url-loader": "^3.0.0", - "webpack": "^4.42.0", - "webpack-bundle-analyzer": "^3.6.1", - "webpack-cli": "^3.3.11", - "webpack-livereload-plugin": "^2.3.0" - } - }, "@wordpress/server-side-render": { "version": "file:packages/server-side-render", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/api-fetch": "file:packages/api-fetch", "@wordpress/components": "file:packages/components", "@wordpress/data": "file:packages/data", @@ -11188,22 +12815,22 @@ "@wordpress/shortcode": { "version": "file:packages/shortcode", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "lodash": "^4.17.15", - "memize": "^1.0.5" + "memize": "^1.1.0" } }, "@wordpress/token-list": { "version": "file:packages/token-list", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "lodash": "^4.17.15" } }, "@wordpress/url": { "version": "file:packages/url", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "lodash": "^4.17.15", "qs": "^6.5.2", "react-native-url-polyfill": "^1.1.2" @@ -11212,7 +12839,7 @@ "@wordpress/viewport": { "version": "file:packages/viewport", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/compose": "file:packages/compose", "@wordpress/data": "file:packages/data", "lodash": "^4.17.15" @@ -11224,7 +12851,7 @@ "@wordpress/wordcount": { "version": "file:packages/wordcount", "requires": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "lodash": "^4.17.15" } }, @@ -11265,9 +12892,10 @@ } }, "abab": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz", - "integrity": "sha1-X6rZwsB/YN12dw9xzwJbYqY8/U4=" + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.3.tgz", + "integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg==", + "dev": true }, "abbrev": { "version": "1.1.1", @@ -11299,14 +12927,31 @@ "acorn": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.1.tgz", - "integrity": "sha512-d+nbxBUGKg7Arpsvbnlq61mc12ek3EY8EQldM3GPAhWJ1UVxC6TDGbIvUMNU6obBX3i1+ptCIzV4vq0gFPEGVQ==" + "integrity": "sha512-d+nbxBUGKg7Arpsvbnlq61mc12ek3EY8EQldM3GPAhWJ1UVxC6TDGbIvUMNU6obBX3i1+ptCIzV4vq0gFPEGVQ==", + "dev": true }, "acorn-globals": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.1.0.tgz", - "integrity": "sha512-KjZwU26uG3u6eZcfGbTULzFcsoz6pegNKtHPksZPOUsiKo5bUmiBPa38FuHZ/Eun+XYh/JCCkS9AS3Lu4McQOQ==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz", + "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==", + "dev": true, "requires": { - "acorn": "^5.0.0" + "acorn": "^6.0.1", + "acorn-walk": "^6.0.1" + }, + "dependencies": { + "acorn": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", + "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==", + "dev": true + }, + "acorn-walk": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", + "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==", + "dev": true + } } }, "acorn-jsx": { @@ -11333,6 +12978,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "dev": true, "requires": { "es6-promisify": "^5.0.0" } @@ -11808,9 +13454,9 @@ } }, "buffer": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.5.0.tgz", - "integrity": "sha512-9FTEDjLjwoAkEwyMGDjYJQN2gfRgOKBKRfiglhvibGbpeeU/pQn1bJxQqm32OD/AIeEuHxU9roxXxg34Byp/Ww==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", "requires": { "base64-js": "^1.0.2", "ieee754": "^1.1.4" @@ -11884,9 +13530,9 @@ } }, "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" }, "normalize-path": { "version": "3.0.0", @@ -12467,6 +14113,26 @@ "postcss-value-parser": "^4.0.0" }, "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "postcss": { "version": "7.0.26", "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.26.tgz", @@ -12513,18 +14179,18 @@ "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" }, "axe-core": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-3.4.0.tgz", - "integrity": "sha512-5C0OdgxPv/DrQguO6Taj5F1dY5OlkWg4SVmZIVABFYKWlnAc5WTLPzG+xJSgIwf2fmY+NiNGiZXhXx2qT0u/9Q==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-3.5.3.tgz", + "integrity": "sha512-HZpLE7xu05+8AbpqXITGdxp1Xwk8ysAXrg7MiKRY27py3DAyEJpoJQo1727pWF3F+O79V3r+cTWhOzfB49P89w==", "dev": true }, "axe-puppeteer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/axe-puppeteer/-/axe-puppeteer-1.0.0.tgz", - "integrity": "sha512-hTF3u4mtatgTN7fsLVyVgbRdNc15ngjDcTEuqhn9A7ugqLhLCryJWp9fzqZkNlrW8awPcxugyTwLPR7mRdPZmA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/axe-puppeteer/-/axe-puppeteer-1.1.0.tgz", + "integrity": "sha512-VS17Y1rDQe6A0PdeTPxwOSBfmOdj6efgxyre9cN1du1snnVilczSDtQsgifBKBlzoL/3DKfGpgIi+N+zrzODOg==", "dev": true, "requires": { - "axe-core": "^3.1.2" + "axe-core": "^3.5.3" } }, "axobject-query": { @@ -12601,14 +14267,14 @@ "dev": true }, "babel-eslint": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.0.3.tgz", - "integrity": "sha512-z3U7eMY6r/3f3/JB9mTsLjyxrv0Yb1zb8PCWCLpguxfCzBIZUwy23R1t/XKewP+8mEN2Ck8Dtr4q20z6ce6SoA==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", + "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", "requires": { "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.0.0", - "@babel/traverse": "^7.0.0", - "@babel/types": "^7.0.0", + "@babel/parser": "^7.7.0", + "@babel/traverse": "^7.7.0", + "@babel/types": "^7.7.0", "eslint-visitor-keys": "^1.0.0", "resolve": "^1.12.0" }, @@ -12619,9 +14285,9 @@ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" }, "resolve": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.0.tgz", - "integrity": "sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw==", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", + "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", "requires": { "path-parse": "^1.0.6" } @@ -12674,6 +14340,7 @@ "version": "24.9.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.9.0.tgz", "integrity": "sha512-ntuddfyiN+EhMw58PTNL1ph4C9rECiQXjI4nMMBKBaNjXvqLdkXpPRcMSr4iyBrJg/+wz9brFUD6RhOAT6r4Iw==", + "dev": true, "requires": { "@jest/transform": "^24.9.0", "@jest/types": "^24.9.0", @@ -12684,73 +14351,11 @@ "slash": "^2.0.0" }, "dependencies": { - "@jest/console": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", - "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", - "requires": { - "@jest/source-map": "^24.9.0", - "chalk": "^2.0.1", - "slash": "^2.0.0" - } - }, - "@jest/fake-timers": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz", - "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", - "requires": { - "@jest/types": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-mock": "^24.9.0" - } - }, - "@jest/source-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", - "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.1.15", - "source-map": "^0.6.0" - } - }, - "@jest/test-result": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", - "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", - "requires": { - "@jest/console": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/istanbul-lib-coverage": "^2.0.0" - } - }, - "@jest/transform": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-24.9.0.tgz", - "integrity": "sha512-TcQUmyNRxV94S0QpMOnZl0++6RMiqpbH/ZMccFB/amku6Uwvyb1cjYX7xkp5nGNkbX4QPH/FcB6q1HBTHynLmQ==", - "requires": { - "@babel/core": "^7.1.0", - "@jest/types": "^24.9.0", - "babel-plugin-istanbul": "^5.1.0", - "chalk": "^2.0.1", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.1.15", - "jest-haste-map": "^24.9.0", - "jest-regex-util": "^24.9.0", - "jest-util": "^24.9.0", - "micromatch": "^3.1.10", - "pirates": "^4.0.1", - "realpath-native": "^1.1.0", - "slash": "^2.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "2.4.1" - } - }, "@jest/types": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^1.1.1", @@ -12758,144 +14363,71 @@ } }, "@types/yargs": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.5.tgz", - "integrity": "sha512-CF/+sxTO7FOwbIRL4wMv0ZYLCRfMid2HQpzDRyViH7kSpfoAFiMdGqKIxb1PxWfjtQXQhnQuD33lvRHNwr809Q==", + "version": "13.0.8", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz", + "integrity": "sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA==", + "dev": true, "requires": { "@types/yargs-parser": "*" } }, - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" - }, - "jest-haste-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.9.0.tgz", - "integrity": "sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ==", - "requires": { - "@jest/types": "^24.9.0", - "anymatch": "^2.0.0", - "fb-watchman": "^2.0.0", - "fsevents": "^1.2.7", - "graceful-fs": "^4.1.15", - "invariant": "^2.2.4", - "jest-serializer": "^24.9.0", - "jest-util": "^24.9.0", - "jest-worker": "^24.9.0", - "micromatch": "^3.1.10", - "sane": "^4.0.3", - "walker": "^1.0.7" - } - }, - "jest-message-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", - "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", - "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/stack-utils": "^1.0.1", - "chalk": "^2.0.1", - "micromatch": "^3.1.10", - "slash": "^2.0.0", - "stack-utils": "^1.0.1" - } - }, - "jest-mock": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz", - "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", - "requires": { - "@jest/types": "^24.9.0" - } - }, - "jest-regex-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz", - "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==" - }, - "jest-serializer": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.9.0.tgz", - "integrity": "sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ==" - }, - "jest-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz", - "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", - "requires": { - "@jest/console": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/source-map": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "callsites": "^3.0.0", - "chalk": "^2.0.1", - "graceful-fs": "^4.1.15", - "is-ci": "^2.0.0", - "mkdirp": "^0.5.1", - "slash": "^2.0.0", - "source-map": "^0.6.0" - } - }, - "jest-worker": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", - "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, "requires": { - "merge-stream": "^2.0.0", - "supports-color": "^6.1.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" - }, "slash": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - }, - "write-file-atomic": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.1.tgz", - "integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==", - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" - } + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true } } }, "babel-loader": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.0.6.tgz", - "integrity": "sha512-4BmWKtBOBm13uoUwd08UwjZlaw3O9GWf456R9j+5YykFZ6LUIjIKLc0zEZf+hauxPOJs96C8k6FvYD09vWzhYw==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.1.0.tgz", + "integrity": "sha512-7q7nC1tYOrqvUrN3LQK4GwSk/TQorZSOlO9C+RZDZpODgyN4ZlCqE5q9cDsyWOliN+aU9B4JX01xK9eJXowJLw==", "requires": { - "find-cache-dir": "^2.0.0", - "loader-utils": "^1.0.2", - "mkdirp": "^0.5.1", - "pify": "^4.0.1" + "find-cache-dir": "^2.1.0", + "loader-utils": "^1.4.0", + "mkdirp": "^0.5.3", + "pify": "^4.0.1", + "schema-utils": "^2.6.5" }, "dependencies": { + "ajv": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz", + "integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==" + }, + "fast-deep-equal": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", + "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==" + }, "find-cache-dir": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", @@ -12914,6 +14446,24 @@ "locate-path": "^3.0.0" } }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + }, "locate-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", @@ -12932,10 +14482,25 @@ "semver": "^5.6.0" } }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + }, + "dependencies": { + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + } + } + }, "p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "requires": { "p-try": "^2.0.0" } @@ -12966,6 +14531,15 @@ "find-up": "^3.0.0" } }, + "schema-utils": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.5.tgz", + "integrity": "sha512-5KXuwKziQrTVHh8j/Uxz+QUbxkaLW9X/86NBlx/gnKgtsZA2GIVMUn17qWhRFwF8jdYb3Dig5hRO/W5mZqy6SQ==", + "requires": { + "ajv": "^6.12.0", + "ajv-keywords": "^3.4.1" + } + }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -12980,19 +14554,19 @@ "dev": true }, "babel-plugin-apply-mdx-type-prop": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/babel-plugin-apply-mdx-type-prop/-/babel-plugin-apply-mdx-type-prop-1.5.5.tgz", - "integrity": "sha512-yaklz3xE5vFtZpPpYC9lDbTqlC6hq0CjgheiLw3i40lY8vG0DINh+HJ7rq1Gi1g0q/iihwetJ+YFGpUM4YXAGA==", + "version": "1.5.8", + "resolved": "https://registry.npmjs.org/babel-plugin-apply-mdx-type-prop/-/babel-plugin-apply-mdx-type-prop-1.5.8.tgz", + "integrity": "sha512-xYp5F9mAnZdDRFSd1vF3XQ0GQUbIulCpnuht2jCmK30GAHL8szVL7TgzwhEGamQ6yJmP/gEyYNM9OR5D2n26eA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.8.0", - "@mdx-js/util": "^1.5.5" + "@babel/helper-plugin-utils": "7.8.3", + "@mdx-js/util": "^1.5.8" }, "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.0.tgz", - "integrity": "sha512-+hAlRGdf8fHQAyNnDBqTHQhwdLURLdrCROoWaEQYiQhk2sV9Rhs+GoFZZfMJExTq9HG8o2NX3uN2G90bFtmFdA==", + "@mdx-js/util": { + "version": "1.5.8", + "resolved": "https://registry.npmjs.org/@mdx-js/util/-/util-1.5.8.tgz", + "integrity": "sha512-a7Gjjw8bfBSertA/pTWBA/9WKEhgaSxvQE2NTSUzaknrzGFOhs4alZSHh3RHmSFdSWv5pUuzAgsWseMLhWEVkQ==", "dev": true } } @@ -13006,14 +14580,14 @@ } }, "babel-plugin-emotion": { - "version": "10.0.27", - "resolved": "https://registry.npmjs.org/babel-plugin-emotion/-/babel-plugin-emotion-10.0.27.tgz", - "integrity": "sha512-SUNYcT4FqhOqvwv0z1oeYhqgheU8qrceLojuHyX17ngo7WtWqN5I9l3IGHzf21Xraj465CVzF4IvOlAF+3ed0A==", + "version": "10.0.33", + "resolved": "https://registry.npmjs.org/babel-plugin-emotion/-/babel-plugin-emotion-10.0.33.tgz", + "integrity": "sha512-bxZbTTGz0AJQDHm8k6Rf3RQJ8tX2scsfsRyKVgAbiUPUNIRtlK+7JxP+TAd1kRLABFxe0CFm2VdK4ePkoA9FxQ==", "requires": { "@babel/helper-module-imports": "^7.0.0", - "@emotion/hash": "0.7.4", + "@emotion/hash": "0.8.0", "@emotion/memoize": "0.7.4", - "@emotion/serialize": "^0.11.15", + "@emotion/serialize": "^0.11.16", "babel-plugin-macros": "^2.0.0", "babel-plugin-syntax-jsx": "^6.18.0", "convert-source-map": "^1.5.0", @@ -13023,9 +14597,9 @@ }, "dependencies": { "@emotion/hash": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.7.4.tgz", - "integrity": "sha512-fxfMSBMX3tlIbKUdtGKxqB1fyrH6gVrX39Gsv3y8lRYKUqlgDt3UMqQyGnR1bQMa2B8aGnhLZokZgg8vT0Le+A==" + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" }, "@emotion/memoize": { "version": "0.7.4", @@ -13033,11 +14607,11 @@ "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==" }, "@emotion/serialize": { - "version": "0.11.15", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.15.tgz", - "integrity": "sha512-YE+qnrmGwyR+XB5j7Bi+0GT1JWsdcjM/d4POu+TXkcnrRs4RFCCsi3d/Ebf+wSStHqAlTT2+dfd+b9N9EO2KBg==", + "version": "0.11.16", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.16.tgz", + "integrity": "sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==", "requires": { - "@emotion/hash": "0.7.4", + "@emotion/hash": "0.8.0", "@emotion/memoize": "0.7.4", "@emotion/unitless": "0.7.5", "@emotion/utils": "0.11.3", @@ -13057,20 +14631,12 @@ } }, "babel-plugin-extract-import-names": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/babel-plugin-extract-import-names/-/babel-plugin-extract-import-names-1.5.5.tgz", - "integrity": "sha512-F9paxnUtO3vddyOX+vbRa8KrkuovJIFB8KmB/dEICqTUm2331LcGbjCKzZApOri4Igbk9MnYybm2fDsuPJC3vA==", + "version": "1.5.8", + "resolved": "https://registry.npmjs.org/babel-plugin-extract-import-names/-/babel-plugin-extract-import-names-1.5.8.tgz", + "integrity": "sha512-LcLfP8ZRBZMdMAXHLugyvvd5PY0gMmLMWFogWAUsG32X6TYW2Eavx+il2bw73KDbW+UdCC1bAJ3NuU25T1MI3g==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.8.0" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.0.tgz", - "integrity": "sha512-+hAlRGdf8fHQAyNnDBqTHQhwdLURLdrCROoWaEQYiQhk2sV9Rhs+GoFZZfMJExTq9HG8o2NX3uN2G90bFtmFdA==", - "dev": true - } + "@babel/helper-plugin-utils": "7.8.3" } }, "babel-plugin-inline-json-import": { @@ -13083,55 +14649,88 @@ } }, "babel-plugin-istanbul": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.1.3.tgz", - "integrity": "sha512-IFyehbvRRwdBlI1lDp+FaMsWNnEndEk7065IB8NhzBX+ZKLPwPodgk4I5Gobw/8SNUUzso2Dv3hbqRh88eiSCQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz", + "integrity": "sha512-5LphC0USA8t4i1zCtjbbNb6jJj/9+X6P37Qfirc/70EQ34xKlMW+a1RHGwxGI+SwWpNwZ27HqvzAobeqaXwiZw==", + "dev": true, "requires": { + "@babel/helper-plugin-utils": "^7.0.0", "find-up": "^3.0.0", - "istanbul-lib-instrument": "^3.2.0", - "test-exclude": "^5.2.2" + "istanbul-lib-instrument": "^3.3.0", + "test-exclude": "^5.2.3" }, "dependencies": { "find-up": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, "requires": { "locate-path": "^3.0.0" } }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, "istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-LXTBICkMARVgo579kWDm8SqfB6nvSDKNqIOBEjmJRnL04JvoMHCYGWaMddQnseJYtkEuEvO/sIcOxPLk9gERug==" + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true }, "istanbul-lib-instrument": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.2.0.tgz", - "integrity": "sha512-06IM3xShbNW4NgZv5AP4QH0oHqf1/ivFo8eFys0ZjPXHGldHJQWb3riYOKXqmOqfxXBfxu4B+g/iuhOPZH0RJg==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", + "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", + "dev": true, "requires": { - "@babel/generator": "^7.0.0", - "@babel/parser": "^7.0.0", - "@babel/template": "^7.0.0", - "@babel/traverse": "^7.0.0", - "@babel/types": "^7.0.0", - "istanbul-lib-coverage": "^2.0.4", + "@babel/generator": "^7.4.0", + "@babel/parser": "^7.4.3", + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.3", + "@babel/types": "^7.4.0", + "istanbul-lib-coverage": "^2.0.5", "semver": "^6.0.0" } }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, "locate-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, "requires": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "p-limit": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", - "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, "requires": { "p-try": "^2.0.0" } @@ -13140,6 +14739,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, "requires": { "p-limit": "^2.0.0" } @@ -13147,12 +14747,69 @@ "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true }, - "semver": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.0.0.tgz", - "integrity": "sha512-0UewU+9rFapKFnlbirLi3byoOuhrSsli/z/ihNnvM24vgF+8sNBiI1LZPBSH9wJKUwaUbw+s3hToDLCXkrghrQ==" + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", + "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "read-pkg": "^3.0.0" + } + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "test-exclude": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", + "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", + "dev": true, + "requires": { + "glob": "^7.1.3", + "minimatch": "^3.0.4", + "read-pkg-up": "^4.0.0", + "require-main-filename": "^2.0.0" + } } } }, @@ -13160,6 +14817,7 @@ "version": "24.9.0", "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.9.0.tgz", "integrity": "sha512-2EMA2P8Vp7lG0RAzr4HXqtYwacfMErOuv1U3wrvxHX6rD1sV6xS3WXG3r8TRQ2r6w8OhvSdWt+z41hQNwNm3Xw==", + "dev": true, "requires": { "@types/babel__traverse": "^7.0.6" } @@ -13208,9 +14866,9 @@ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" }, "resolve": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.0.tgz", - "integrity": "sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw==", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", + "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", "requires": { "path-parse": "^1.0.6" } @@ -13312,9 +14970,9 @@ } }, "babel-plugin-named-asset-import": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.5.tgz", - "integrity": "sha512-sGhfINU+AuMw9oFAdIn/nD5sem3pn/WgxAfDZ//Q3CnF+5uaho7C7shh2rKLk6sKE/XkfmyibghocwKdVjLIKg==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.6.tgz", + "integrity": "sha512-1aGDUfL1qOOIoqk9QKGIo2lANk+C7ko/fqH0uIyC71x3PEGz0uVP8ISgfEsFuG+FKmjHTvFK/nNM8dowpmUxLA==", "dev": true }, "babel-plugin-react-docgen": { @@ -13463,10 +15121,27 @@ "integrity": "sha1-viQcqBQEAwZ4t0hxcyK4nQyP4oA=", "dev": true }, + "babel-preset-current-node-syntax": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-0.1.2.tgz", + "integrity": "sha512-u/8cS+dEiK1SFILbOC8/rUI3ml9lboKuuMvZ/4aQnQmhecQAgPw5ew066C1ObnEAUmlx7dv/s2z52psWEtLNiw==", + "requires": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + } + }, "babel-preset-fbjs": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/babel-preset-fbjs/-/babel-preset-fbjs-3.2.0.tgz", - "integrity": "sha512-5Jo+JeWiVz2wHUUyAlvb/sSYnXNig9r+HqGAOSfh5Fzxp7SnAaR/tEGRJ1ZX7C77kfk82658w6R5Z+uPATTD9g==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/babel-preset-fbjs/-/babel-preset-fbjs-3.3.0.tgz", + "integrity": "sha512-7QTLTCd2gwB2qGoi5epSULMHugSVgpcVt5YAeiFO9ABLrutDQzKfGwzxgZHLpugq8qMdg/DhRZDZ5CLKxBkEbw==", "requires": { "@babel/plugin-proposal-class-properties": "^7.0.0", "@babel/plugin-proposal-object-rest-spread": "^7.0.0", @@ -13501,6 +15176,7 @@ "version": "24.9.0", "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-24.9.0.tgz", "integrity": "sha512-izTUuhE4TMfTRPF92fFwD2QfdXaZW08qvWTFCI51V8rW5x00UuPgc3ajRoWofXOuxjfcOM5zzSYsQS3H8KGCAg==", + "dev": true, "requires": { "@babel/plugin-syntax-object-rest-spread": "^7.0.0", "babel-plugin-jest-hoist": "^24.9.0" @@ -13647,6 +15323,11 @@ } } }, + "base-64": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz", + "integrity": "sha1-eAqZyE59YAJgNhURxId2E78k9rs=" + }, "base64-js": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", @@ -13858,9 +15539,9 @@ } }, "body-scroll-lock": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/body-scroll-lock/-/body-scroll-lock-2.6.4.tgz", - "integrity": "sha512-NP08WsovlmxEoZP9pdlqrE+AhNaivlTrz9a0FF37BQsnOrpN48eNqivKkE7SYpM9N+YIPjsdVzfLAUQDBm6OQw==" + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/body-scroll-lock/-/body-scroll-lock-2.7.1.tgz", + "integrity": "sha512-hS53SQ8RhM0e4DsQ3PKz6Gr2O7Kpdh59TWU98GHjaQznL7y4dFycEPk7pFQAikqBaUSCArkc5E3pe7CWIt2fZA==" }, "boolbase": { "version": "1.0.0", @@ -13977,6 +15658,12 @@ "has-flag": "^4.0.0" } }, + "term-size": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.0.tgz", + "integrity": "sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw==", + "dev": true + }, "type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", @@ -14282,6 +15969,31 @@ "y18n": "^4.0.0" }, "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + }, + "dependencies": { + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, "y18n": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", @@ -14306,6 +16018,58 @@ "unset-value": "^1.0.0" } }, + "cacheable-lookup": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-2.0.1.tgz", + "integrity": "sha512-EMMbsiOTcdngM/K6gV/OxF2x0t07+vMOWxZNSCRQMjO2MY2nhZQ6OYhOOpyQrbhqsgtvKGI7hcq6xjnA92USjg==", + "requires": { + "@types/keyv": "^3.1.1", + "keyv": "^4.0.0" + } + }, + "cacheable-request": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.1.tgz", + "integrity": "sha512-lt0mJ6YAnsrBErpTMWeu5kl/tg9xMAWjavYTN6VQXM1A/teBITuNcccXsCxF0tDQQJf9DfAaX5O4e0zp0KlfZw==", + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^2.0.0" + }, + "dependencies": { + "get-stream": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", + "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "requires": { + "pump": "^3.0.0" + } + }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" + }, + "normalize-url": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", + "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==" + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, "call-me-maybe": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", @@ -14454,13 +16218,49 @@ } }, "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz", + "integrity": "sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "requires": { + "has-flag": "^4.0.0" + } + } } }, "character-entities": { @@ -14511,6 +16311,16 @@ "semver": "^5.0.3" }, "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -14523,19 +16333,6 @@ "resolved": "https://registry.npmjs.org/check-types/-/check-types-8.0.3.tgz", "integrity": "sha512-YpeKZngUmG65rLudJ4taU7VLkOCTMhNl/u4ctNC56LQS/zJTyNH0Lrtwm1tfTsbLlwvlfsA2d1c8vCf/Kh2KwQ==" }, - "cheerio": { - "version": "1.0.0-rc.2", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.2.tgz", - "integrity": "sha1-S59TqBsn5NXawxwP/Qz6A8xoMNs=", - "requires": { - "css-select": "~1.2.0", - "dom-serializer": "~0.1.0", - "entities": "~1.1.1", - "htmlparser2": "^3.9.1", - "lodash": "^4.15.0", - "parse5": "^3.0.1" - } - }, "chokidar": { "version": "2.1.8", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", @@ -14792,6 +16589,21 @@ "is-supported-regexp-flag": "^1.0.0" } }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "requires": { + "mimic-response": "^1.0.0" + }, + "dependencies": { + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" + } + } + }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -14805,6 +16617,18 @@ "@types/q": "^1.5.1", "chalk": "^2.4.1", "q": "^1.1.2" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } } }, "code-point-at": { @@ -14817,6 +16641,11 @@ "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.4.tgz", "integrity": "sha512-YfQ1tAUZm561vpYD+5eyWN8+UsceQbSrqqlc/6zDY2gtAE+uZLSdkkovhnGpmCThsvKBFakq4EdY/FF93E8XIw==" }, + "collect-v8-coverage": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.0.tgz", + "integrity": "sha512-VKIhJgvk8E1W28m5avZ2Gv2Ruv5YiF56ug2oclvaG9md69BuZImMG2sk9g7QNKLUbtYAKQjXjYxbYZVUlMMKmQ==" + }, "collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", @@ -14927,9 +16756,9 @@ "dev": true }, "comment-parser": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-0.6.1.tgz", - "integrity": "sha512-Putzd7Ilyvknmb1KxGf5el9uw0sPx9gEVnDrm8tlvXGN1i8Uaa2VBxB32hUhfzTlrEhhxNQ+pKq4ZNe8wNxjmw==" + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-0.7.2.tgz", + "integrity": "sha512-4Rjb1FnxtOcv9qsfuaNuVsmmVn4ooVoBHzYfyKteiXwIU84PClyGA5jASoFMwPV93+FPh9spwueXauxFJZkGAg==" }, "commondir": { "version": "1.0.1", @@ -15702,6 +17531,29 @@ "mkdirp": "^0.5.1", "rimraf": "^2.5.4", "run-queue": "^1.0.0" + }, + "dependencies": { + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + } } }, "copy-descriptor": { @@ -15789,15 +17641,30 @@ } }, "core-js": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.1.4.tgz", - "integrity": "sha512-YNZN8lt82XIMLnLirj9MhKDFZHalwzzrL9YLt6eb0T5D0EDl4IQ90IGkua8mHbnxNrkj1d8hbdizMc0Qmg1WnQ==" + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.4.tgz", + "integrity": "sha512-4paDGScNgZP2IXXilaffL9X7968RuvwlkK3xWtZRVqgd8SYNiVKRJvkFd1aqqEuPfN7E68ZHEp9hDj6lHj4Hyw==" + }, + "core-js-compat": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.6.4.tgz", + "integrity": "sha512-zAa3IZPvsJ0slViBQ2z+vgyyTuhd3MFn1rBQjZSKVEgB0UMYhUkCj9jJUVPgGTGqWvsBVmfnruXgTcNyTlEiSA==", + "requires": { + "browserslist": "^4.8.3", + "semver": "7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==" + } + } }, "core-js-pure": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.2.1.tgz", - "integrity": "sha512-+qpvnYrsi/JDeQTArB7NnNc2VoMYLE1YSkziCDHgjexC2KH7OFiGhLUd3urxfyWmNjSwSW7NYXPWHMhuIJx9Ow==", - "dev": true + "integrity": "sha512-+qpvnYrsi/JDeQTArB7NnNc2VoMYLE1YSkziCDHgjexC2KH7OFiGhLUd3urxfyWmNjSwSW7NYXPWHMhuIJx9Ow==" }, "core-util-is": { "version": "1.0.2", @@ -15852,9 +17719,9 @@ }, "dependencies": { "buffer": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.5.0.tgz", - "integrity": "sha512-9FTEDjLjwoAkEwyMGDjYJQN2gfRgOKBKRfiglhvibGbpeeU/pQn1bJxQqm32OD/AIeEuHxU9roxXxg34Byp/Ww==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", "requires": { "base64-js": "^1.0.2", "ieee754": "^1.1.4" @@ -16118,6 +17985,30 @@ "chalk": "^2.4.2", "source-map": "^0.6.1", "supports-color": "^6.1.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + } } }, "postcss-modules-extract-imports": { @@ -16366,9 +18257,25 @@ } }, "cssom": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.4.tgz", - "integrity": "sha512-+7prCSORpXNeR4/fUP3rL+TzqtiFfhMvTd7uEqMdgPvLPt4+uzFUeufx5RHjGTACCargg/DiEt/moMQmvnfkog==" + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + }, + "cssstyle": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.2.0.tgz", + "integrity": "sha512-sEb3XFPx3jNnCAMtqrXPDeSgQr+jojtCeNf8cvMNMh1cG970+lljssvQDzPq6lmmJu2Vhqood/gtEomBiHOGnA==", + "requires": { + "cssom": "~0.3.6" + }, + "dependencies": { + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" + } + } }, "csstype": { "version": "2.6.7", @@ -16420,13 +18327,27 @@ } }, "data-urls": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.0.0.tgz", - "integrity": "sha512-ai40PPQR0Fn1lD2PPie79CibnlMN2AYiDhwFX/rZHVsxbs5kNJSjegqXIprhouGXlRdEnfybva7kqRGnB6mypA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", + "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", + "dev": true, "requires": { - "abab": "^1.0.4", - "whatwg-mimetype": "^2.0.0", - "whatwg-url": "^6.4.0" + "abab": "^2.0.0", + "whatwg-mimetype": "^2.2.0", + "whatwg-url": "^7.0.0" + }, + "dependencies": { + "whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + } } }, "date-fns": { @@ -16501,6 +18422,14 @@ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" }, + "decompress-response": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-5.0.0.tgz", + "integrity": "sha512-TLZWWybuxWgoW7Lykv+gq9xvzOsUjQ9tF09Tj6NSTYGMTCHNXzrPnD6Hi+TgZq19PyTAGH4Ll/NIM/eTGglnMw==", + "requires": { + "mimic-response": "^2.0.0" + } + }, "decompress-zip": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/decompress-zip/-/decompress-zip-0.2.2.tgz", @@ -16601,6 +18530,11 @@ "clone": "^1.0.2" } }, + "defer-to-connect": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.0.tgz", + "integrity": "sha512-bYL2d05vOSf1JEZNx5vSAtPuBMkX8K9EUutg7zlKvTqKXHt7RhWJFbmd7qakVuf13i+IkGmp6FwSsONOf6VYIg==" + }, "define-properties": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", @@ -16902,7 +18836,8 @@ "detect-newline": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", - "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=" + "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", + "dev": true }, "detect-node": { "version": "2.0.4", @@ -16947,9 +18882,10 @@ "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" }, "diff-sequences": { - "version": "24.3.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.3.0.tgz", - "integrity": "sha512-xLqpez+Zj9GKSnPWS0WZw1igGocZ+uua8+y+5dDNTT934N3QuY1sp2LkHzwiaYQGz60hMq0pjAshdeXm5VUOEw==" + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz", + "integrity": "sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==", + "dev": true }, "diffie-hellman": { "version": "5.0.3", @@ -17006,6 +18942,12 @@ "integrity": "sha1-6oCxBqh1OHdOijpKWv4pPeSJ4Kk=", "dev": true }, + "dom-accessibility-api": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.4.3.tgz", + "integrity": "sha512-JZ8iPuEHDQzq6q0k7PKMGbrIdsgBB7TRrtVOUm4nSMCExlg5qQG4KXWTH2k90yggjM4tTumRGwTKJSldMzKyLA==", + "dev": true + }, "dom-converter": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", @@ -17147,6 +19089,11 @@ "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=" }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" + }, "duplexify": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.0.tgz", @@ -17211,11 +19158,6 @@ "minimalistic-crypto-utils": "^1.0.0" } }, - "eme-encryption-scheme-polyfill": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/eme-encryption-scheme-polyfill/-/eme-encryption-scheme-polyfill-2.0.1.tgz", - "integrity": "sha512-Wz+Ro1c0/2Wsx2RLFvTOO0m4LvYn+7cSnq3XOvRvLLBq8jbvUACH/zpU9s0/5+mQa5oaelkU69x+q0z/iWYrFA==" - }, "emoji-regex": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", @@ -17299,67 +19241,373 @@ "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", "requires": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + } + } + }, + "entities": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", + "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=" + }, + "env-paths": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-1.0.0.tgz", + "integrity": "sha1-QWgTO0K7BcOKNbGuQ5fIKYqzaeA=", + "dev": true + }, + "envinfo": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.5.0.tgz", + "integrity": "sha512-jDgnJaF/Btomk+m3PZDTTCb5XIIIX3zYItnCRfF73zVgvinLoRomuhi75Y4su0PtQxWz4v66XnLLckyvyJTOIQ==" + }, + "enzyme": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/enzyme/-/enzyme-3.11.0.tgz", + "integrity": "sha512-Dw8/Gs4vRjxY6/6i9wU0V+utmQO9kvh9XLnz3LIudviOnVYDEe2ec+0k+NQoMamn1VrjKgCUOWj5jG/5M5M0Qw==", + "requires": { + "array.prototype.flat": "^1.2.3", + "cheerio": "^1.0.0-rc.3", + "enzyme-shallow-equal": "^1.0.1", + "function.prototype.name": "^1.1.2", + "has": "^1.0.3", + "html-element-map": "^1.2.0", + "is-boolean-object": "^1.0.1", + "is-callable": "^1.1.5", + "is-number-object": "^1.0.4", + "is-regex": "^1.0.5", + "is-string": "^1.0.5", + "is-subset": "^0.1.1", + "lodash.escape": "^4.0.1", + "lodash.isequal": "^4.5.0", + "object-inspect": "^1.7.0", + "object-is": "^1.0.2", + "object.assign": "^4.1.0", + "object.entries": "^1.1.1", + "object.values": "^1.1.1", + "raf": "^3.4.1", + "rst-selector-parser": "^2.2.3", + "string.prototype.trim": "^1.2.1" + }, + "dependencies": { + "array.prototype.flat": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz", + "integrity": "sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + } + } + }, + "cheerio": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.3.tgz", + "integrity": "sha512-0td5ijfUPuubwLUu0OBoe98gZj8C/AA+RW3v67GPlGOrvxWjZmBXiBCRU+I8VEiNyJzjth40POfHiz2RB3gImA==", + "requires": { + "css-select": "~1.2.0", + "dom-serializer": "~0.1.1", + "entities": "~1.1.1", + "htmlparser2": "^3.9.1", + "lodash": "^4.15.0", + "parse5": "^3.0.1" + } + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "requires": { + "object-keys": "^1.0.12" + } + }, + "dom-serializer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", + "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", + "requires": { + "domelementtype": "^1.3.0", + "entities": "^1.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "function.prototype.name": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.2.tgz", + "integrity": "sha512-C8A+LlHBJjB2AdcRPorc5JvJ5VUoWlXdEHLOJdCI7kjHEtGTpHQUiqMvCIKUwIsGwZX2jZJy761AXsn356bJQg==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "functions-have-names": "^1.2.0" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + } + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==" + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "requires": { + "has": "^1.0.3" + } + }, + "is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==" + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "requires": { + "has-symbols": "^1.0.1" + } + }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==" + }, + "object-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.2.tgz", + "integrity": "sha512-Epah+btZd5wrrfjkJZq1AOB9O6OxUQto45hzFd7lXGrpHPGE0W1k+426yrZV+k6NJOzLNNW/nVsmZdIWsAqoOQ==" + }, + "object.entries": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.1.tgz", + "integrity": "sha512-ilqR7BgdyZetJutmDPfXCDffGa0/Yzl2ivVNpbx/g4UeWrCdRnFDUBrKJGLhGieRHDATnyZXWBeCb29k9CJysQ==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + } + } + }, + "object.values": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", + "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + } + } + }, + "react-is": { + "version": "16.8.6", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz", + "integrity": "sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA==" + }, + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + }, + "string.prototype.trimleft": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz", + "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimstart": "^1.0.0" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + } + } + }, + "string.prototype.trimright": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz", + "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimend": "^1.0.0" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + } } } } }, - "entities": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", - "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=" - }, - "env-paths": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-1.0.0.tgz", - "integrity": "sha1-QWgTO0K7BcOKNbGuQ5fIKYqzaeA=", - "dev": true - }, - "envinfo": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.5.0.tgz", - "integrity": "sha512-jDgnJaF/Btomk+m3PZDTTCb5XIIIX3zYItnCRfF73zVgvinLoRomuhi75Y4su0PtQxWz4v66XnLLckyvyJTOIQ==" - }, - "enzyme": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/enzyme/-/enzyme-3.9.0.tgz", - "integrity": "sha512-JqxI2BRFHbmiP7/UFqvsjxTirWoM1HfeaJrmVSZ9a1EADKkZgdPcAuISPMpoUiHlac9J4dYt81MC5BBIrbJGMg==", - "requires": { - "array.prototype.flat": "^1.2.1", - "cheerio": "^1.0.0-rc.2", - "function.prototype.name": "^1.1.0", - "has": "^1.0.3", - "html-element-map": "^1.0.0", - "is-boolean-object": "^1.0.0", - "is-callable": "^1.1.4", - "is-number-object": "^1.0.3", - "is-regex": "^1.0.4", - "is-string": "^1.0.4", - "is-subset": "^0.1.1", - "lodash.escape": "^4.0.1", - "lodash.isequal": "^4.5.0", - "object-inspect": "^1.6.0", - "object-is": "^1.0.1", - "object.assign": "^4.1.0", - "object.entries": "^1.0.4", - "object.values": "^1.0.4", - "raf": "^3.4.0", - "rst-selector-parser": "^2.2.3", - "string.prototype.trim": "^1.1.2" - } - }, "enzyme-adapter-react-16": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.14.0.tgz", - "integrity": "sha512-7PcOF7pb4hJUvjY7oAuPGpq3BmlCig3kxXGi2kFx0YzJHppqX1K8IIV9skT1IirxXlu8W7bneKi+oQ10QRnhcA==", + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.15.2.tgz", + "integrity": "sha512-SkvDrb8xU3lSxID8Qic9rB8pvevDbLybxPK6D/vW7PrT0s2Cl/zJYuXvsd1EBTz0q4o3iqG3FJhpYz3nUNpM2Q==", "requires": { - "enzyme-adapter-utils": "^1.12.0", + "enzyme-adapter-utils": "^1.13.0", + "enzyme-shallow-equal": "^1.0.1", "has": "^1.0.3", "object.assign": "^4.1.0", - "object.values": "^1.1.0", + "object.values": "^1.1.1", "prop-types": "^15.7.2", - "react-is": "^16.8.6", + "react-is": "^16.12.0", "react-test-renderer": "^16.0.0-0", "semver": "^5.7.0" }, @@ -17372,49 +19620,133 @@ "object-keys": "^1.0.12" } }, + "es-abstract": { + "version": "1.17.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz", + "integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + }, + "dependencies": { + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + } + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==" + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "requires": { + "has": "^1.0.3" + } + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "requires": { + "has-symbols": "^1.0.1" + } + }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==" + }, "object.values": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz", - "integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", + "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", "requires": { "define-properties": "^1.1.3", - "es-abstract": "^1.12.0", + "es-abstract": "^1.17.0-next.1", "function-bind": "^1.1.1", "has": "^1.0.3" } }, "react-is": { - "version": "16.8.6", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz", - "integrity": "sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA==" + "version": "16.13.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.0.tgz", + "integrity": "sha512-GFMtL0vHkiBv9HluwNZTggSn/sCyEt9n02aM0dSAjGGyqyNlAyftYm4phPxdvCigG15JreC5biwxCgTAJZ7yAA==" }, "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "string.prototype.trimleft": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", + "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string.prototype.trimright": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", + "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } } } }, "enzyme-adapter-utils": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/enzyme-adapter-utils/-/enzyme-adapter-utils-1.12.0.tgz", - "integrity": "sha512-wkZvE0VxcFx/8ZsBw0iAbk3gR1d9hK447ebnSYBf95+r32ezBq+XDSAvRErkc4LZosgH8J7et7H7/7CtUuQfBA==", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/enzyme-adapter-utils/-/enzyme-adapter-utils-1.13.0.tgz", + "integrity": "sha512-YuEtfQp76Lj5TG1NvtP2eGJnFKogk/zT70fyYHXK2j3v6CtuHqc8YmgH/vaiBfL8K1SgVVbQXtTcgQZFwzTVyQ==", "requires": { - "airbnb-prop-types": "^2.13.2", - "function.prototype.name": "^1.1.0", + "airbnb-prop-types": "^2.15.0", + "function.prototype.name": "^1.1.2", "object.assign": "^4.1.0", - "object.fromentries": "^2.0.0", + "object.fromentries": "^2.0.2", "prop-types": "^15.7.2", - "semver": "^5.6.0" + "semver": "^5.7.1" }, "dependencies": { "airbnb-prop-types": { - "version": "2.13.2", - "resolved": "https://registry.npmjs.org/airbnb-prop-types/-/airbnb-prop-types-2.13.2.tgz", - "integrity": "sha512-2FN6DlHr6JCSxPPi25EnqGaXC4OC3/B3k1lCd6MMYrZ51/Gf/1qDfaR+JElzWa+Tl7cY2aYOlsYJGFeQyVHIeQ==", + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/airbnb-prop-types/-/airbnb-prop-types-2.15.0.tgz", + "integrity": "sha512-jUh2/hfKsRjNFC4XONQrxo/n/3GG4Tn6Hl0WlFQN5PY9OMC9loSCoAYKnZsWaP8wEfd5xcrPloK0Zg6iS1xwVA==", "requires": { - "array.prototype.find": "^2.0.4", - "function.prototype.name": "^1.1.0", + "array.prototype.find": "^2.1.0", + "function.prototype.name": "^1.1.1", "has": "^1.0.3", "is-regex": "^1.0.4", "object-is": "^1.0.1", @@ -17422,7 +19754,7 @@ "object.entries": "^1.1.0", "prop-types": "^15.7.2", "prop-types-exact": "^1.2.0", - "react-is": "^16.8.6" + "react-is": "^16.9.0" } }, "define-properties": { @@ -17433,35 +19765,164 @@ "object-keys": "^1.0.12" } }, + "es-abstract": { + "version": "1.17.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz", + "integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + }, + "dependencies": { + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "requires": { + "has": "^1.0.3" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + } + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "function.prototype.name": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.2.tgz", + "integrity": "sha512-C8A+LlHBJjB2AdcRPorc5JvJ5VUoWlXdEHLOJdCI7kjHEtGTpHQUiqMvCIKUwIsGwZX2jZJy761AXsn356bJQg==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "functions-have-names": "^1.2.0" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==" + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "requires": { + "has-symbols": "^1.0.1" + } + }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==" + }, "object.entries": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.0.tgz", - "integrity": "sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.1.tgz", + "integrity": "sha512-ilqR7BgdyZetJutmDPfXCDffGa0/Yzl2ivVNpbx/g4UeWrCdRnFDUBrKJGLhGieRHDATnyZXWBeCb29k9CJysQ==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "object.fromentries": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.2.tgz", + "integrity": "sha512-r3ZiBH7MQppDJVLx6fhD618GKNG40CZYH9wgwdhKxBDDbQgjeWGGd4AtkZad84d291YxvWe7bJGuE65Anh0dxQ==", "requires": { "define-properties": "^1.1.3", - "es-abstract": "^1.12.0", + "es-abstract": "^1.17.0-next.1", "function-bind": "^1.1.1", "has": "^1.0.3" } }, "react-is": { - "version": "16.8.6", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz", - "integrity": "sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA==" + "version": "16.13.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.0.tgz", + "integrity": "sha512-GFMtL0vHkiBv9HluwNZTggSn/sCyEt9n02aM0dSAjGGyqyNlAyftYm4phPxdvCigG15JreC5biwxCgTAJZ7yAA==" }, "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "string.prototype.trimleft": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", + "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string.prototype.trimright": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", + "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + } + } + }, + "enzyme-shallow-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/enzyme-shallow-equal/-/enzyme-shallow-equal-1.0.1.tgz", + "integrity": "sha512-hGA3i1so8OrYOZSM9whlkNmVHOicJpsjgTzC+wn2JMJXhq1oO4kA4bJ5MsfzSIcC71aLDKzJ6gZpIxrqt3QTAQ==", + "requires": { + "has": "^1.0.3", + "object-is": "^1.0.2" + }, + "dependencies": { + "object-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.2.tgz", + "integrity": "sha512-Epah+btZd5wrrfjkJZq1AOB9O6OxUQto45hzFd7lXGrpHPGE0W1k+426yrZV+k6NJOzLNNW/nVsmZdIWsAqoOQ==" } } }, "enzyme-to-json": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/enzyme-to-json/-/enzyme-to-json-3.3.5.tgz", - "integrity": "sha512-DmH1wJ68HyPqKSYXdQqB33ZotwfUhwQZW3IGXaNXgR69Iodaoj8TF/D9RjLdz4pEhGq2Tx2zwNUIjBuqoZeTgA==", + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/enzyme-to-json/-/enzyme-to-json-3.4.4.tgz", + "integrity": "sha512-50LELP/SCPJJGic5rAARvU7pgE3m1YaNj7JLM+Qkhl5t7PAs6fiyc8xzc50RnkKPFQCv0EeFVjEWdIFRGPWMsA==", "requires": { - "lodash": "^4.17.4" + "lodash": "^4.17.15", + "react-is": "^16.12.0" + }, + "dependencies": { + "react-is": { + "version": "16.13.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.0.tgz", + "integrity": "sha512-GFMtL0vHkiBv9HluwNZTggSn/sCyEt9n02aM0dSAjGGyqyNlAyftYm4phPxdvCigG15JreC5biwxCgTAJZ7yAA==" + } } }, "equivalent-key-map": { @@ -17484,11 +19945,12 @@ } }, "error": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/error/-/error-7.2.1.tgz", - "integrity": "sha512-fo9HBvWnx3NGUKMvMwB/CBCMMrfEJgbDTVDEkPygA3Bdd3lM1OyCd+rbQ8BwnpF6GdVeOLDNmyL4N5Bg80ZvdA==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/error/-/error-7.0.2.tgz", + "integrity": "sha1-pfdf/02ZJhJt2sDqXcOOaJFTywI=", "requires": { - "string-template": "~0.2.1" + "string-template": "~0.2.1", + "xtend": "~4.0.0" } }, "error-ex": { @@ -17698,12 +20160,14 @@ "es6-promise": { "version": "4.2.8", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true }, "es6-promisify": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "dev": true, "requires": { "es6-promise": "^4.0.3" } @@ -17725,11 +20189,12 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "escodegen": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.10.0.tgz", - "integrity": "sha512-fjUOf8johsv23WuIKdNQU4P9t9jhQ4Qzx6pC2uW890OloK3Zs1ZAoCNpg/2larNF501jLl3UNy0kIRcF6VI22g==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.1.tgz", + "integrity": "sha512-Bmt7NcRySdIfNPfU2ZoXDrrXsG9ZjvDxcAlMfDUgRBjLOWTuIACXPBFJH7Z+cLb40JeQco5toikyc9t9P8E9SQ==", + "dev": true, "requires": { - "esprima": "^3.1.3", + "esprima": "^4.0.1", "estraverse": "^4.2.0", "esutils": "^2.0.2", "optionator": "^0.8.1", @@ -17740,14 +20205,15 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, "optional": true } } }, "eslint": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.1.0.tgz", - "integrity": "sha512-QhrbdRD7ofuV09IuE2ySWBz0FyXCq0rriLTZXZqaWSI79CVtHVRdkFuFTViiqzZhkCgfOh9USpriuGN2gIpZDQ==", + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", "requires": { "@babel/code-frame": "^7.0.0", "ajv": "^6.10.0", @@ -17756,19 +20222,19 @@ "debug": "^4.0.1", "doctrine": "^3.0.0", "eslint-scope": "^5.0.0", - "eslint-utils": "^1.3.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^6.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", "esquery": "^1.0.1", "esutils": "^2.0.2", "file-entry-cache": "^5.0.1", "functional-red-black-tree": "^1.0.1", "glob-parent": "^5.0.0", - "globals": "^11.7.0", + "globals": "^12.1.0", "ignore": "^4.0.6", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", - "inquirer": "^6.4.1", + "inquirer": "^7.0.0", "is-glob": "^4.0.0", "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", @@ -17777,7 +20243,7 @@ "minimatch": "^3.0.4", "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", - "optionator": "^0.8.2", + "optionator": "^0.8.3", "progress": "^2.0.0", "regexpp": "^2.0.1", "semver": "^6.1.2", @@ -17789,25 +20255,30 @@ }, "dependencies": { "acorn": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz", - "integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==" + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz", + "integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==" }, "acorn-jsx": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.1.0.tgz", - "integrity": "sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw==" - }, - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==" + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", + "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==" }, "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -17852,27 +20323,33 @@ "estraverse": "^4.1.1" } }, + "eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==" + }, "espree": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.2.tgz", - "integrity": "sha512-2iUPuuPP+yW1PZaMSDM9eyVf8D5P0Hi8h83YtZ5bPc/zHYjII5khoixIUTMO794NOY8F/ThF1Bo8ncZILarUTA==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", + "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", "requires": { - "acorn": "^7.1.0", - "acorn-jsx": "^5.1.0", + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", "eslint-visitor-keys": "^1.1.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", - "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==" - } } }, "glob-parent": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", - "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", "requires": { "is-glob": "^4.0.1" }, @@ -17888,40 +20365,36 @@ } }, "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "requires": { + "type-fest": "^0.8.1" + } }, "ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==" }, - "inquirer": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", - "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", - "requires": { - "ansi-escapes": "^3.2.0", - "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.3", - "figures": "^2.0.0", - "lodash": "^4.17.12", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^6.4.0", - "string-width": "^2.1.0", - "strip-ansi": "^5.1.0", - "through": "^2.3.6" - } - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -17937,6 +20410,16 @@ "is-fullwidth-code-point": "^2.0.0" } }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", @@ -17946,9 +20429,9 @@ } }, "strip-json-comments": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", - "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.0.tgz", + "integrity": "sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w==" }, "table": { "version": "5.4.6", @@ -17959,26 +20442,19 @@ "lodash": "^4.17.14", "slice-ansi": "^2.1.0", "string-width": "^3.0.0" - }, - "dependencies": { - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - } } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" } } }, "eslint-config-prettier": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.10.0.tgz", - "integrity": "sha512-AtndijGte1rPILInUdHjvKEGbIV06NuvPrqlIEaEaWtbtvJh464mDeyGMdZEQMsGvC0ZVkiex1fSNcC4HAbRGg==", + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.10.1.tgz", + "integrity": "sha512-svTy6zh1ecQojvpbJSgH3aei/Rt7C6i090l5f2WQ4aB05lYHeZIR1qL4wZyyILTbtmnbHP5Yn8MrsOJMGa8RkQ==", "requires": { "get-stdin": "^6.0.0" }, @@ -17991,13 +20467,13 @@ } }, "eslint-import-resolver-node": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", - "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.3.tgz", + "integrity": "sha512-b8crLDo0M5RSe5YG8Pu2DYBj71tSB6OvXkfzwbJU2w7y8P4/yo0MyF8jU26IEuEuHF2K5/gcAJE3LhQGqBBbVg==", "dev": true, "requires": { "debug": "^2.6.9", - "resolve": "^1.5.0" + "resolve": "^1.13.1" }, "dependencies": { "debug": { @@ -18008,16 +20484,31 @@ "requires": { "ms": "2.0.0" } + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "resolve": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", + "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } } } }, "eslint-module-utils": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.4.1.tgz", - "integrity": "sha512-H6DOj+ejw7Tesdgbfs4jeS4YMFrT8uI8xwd1gtQqXssaR0EQ26L+2O/w6wkYFy2MymON0fTwHmXBvvfLNZVZEw==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz", + "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==", "dev": true, "requires": { - "debug": "^2.6.8", + "debug": "^2.6.9", "pkg-dir": "^2.0.0" }, "dependencies": { @@ -18051,22 +20542,23 @@ } }, "eslint-plugin-import": { - "version": "2.18.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.18.2.tgz", - "integrity": "sha512-5ohpsHAiUBRNaBWAF08izwUGlbrJoJJ+W9/TBwsGoR1MnlgfwMIKrFeSjWbt6moabiXW9xNvtFz+97KHRfI4HQ==", + "version": "2.20.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.20.2.tgz", + "integrity": "sha512-FObidqpXrR8OnCh4iNsxy+WACztJLXAHBO5hK79T1Hc77PgQZkyDGA5Ag9xAvRpglvLNxhH/zSmZ70/pZ31dHg==", "dev": true, "requires": { "array-includes": "^3.0.3", + "array.prototype.flat": "^1.2.1", "contains-path": "^0.1.0", "debug": "^2.6.9", "doctrine": "1.5.0", "eslint-import-resolver-node": "^0.3.2", - "eslint-module-utils": "^2.4.0", + "eslint-module-utils": "^2.4.1", "has": "^1.0.3", "minimatch": "^3.0.4", "object.values": "^1.1.0", "read-pkg-up": "^2.0.0", - "resolve": "^1.11.0" + "resolve": "^1.12.0" }, "dependencies": { "debug": { @@ -18097,6 +20589,74 @@ "isarray": "^1.0.0" } }, + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + }, + "dependencies": { + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + } + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, "load-json-file": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", @@ -18109,14 +20669,20 @@ "strip-bom": "^3.0.0" } }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", + "dev": true + }, "object.values": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz", - "integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", + "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", "dev": true, "requires": { "define-properties": "^1.1.3", - "es-abstract": "^1.12.0", + "es-abstract": "^1.17.0-next.1", "function-bind": "^1.1.1", "has": "^1.0.3" } @@ -18158,14 +20724,36 @@ } }, "resolve": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", - "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", + "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", "dev": true, "requires": { "path-parse": "^1.0.6" } }, + "string.prototype.trimleft": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz", + "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimstart": "^1.0.0" + } + }, + "string.prototype.trimright": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz", + "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimend": "^1.0.0" + } + }, "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -18175,25 +20763,25 @@ } }, "eslint-plugin-jest": { - "version": "22.15.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-22.15.1.tgz", - "integrity": "sha512-CWq/RR/3tLaKFB+FZcCJwU9hH5q/bKeO3rFP8G07+q7hcDCFNqpvdphVbEbGE6o6qo1UbciEev4ejUWv7brUhw==", + "version": "23.8.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-23.8.2.tgz", + "integrity": "sha512-xwbnvOsotSV27MtAe7s8uGWOori0nUsrXh2f1EnpmXua8sDfY6VZhHAhHg2sqK7HBNycRQExF074XSZ7DvfoFg==", "requires": { - "@typescript-eslint/experimental-utils": "^1.13.0" + "@typescript-eslint/experimental-utils": "^2.5.0" } }, "eslint-plugin-jsdoc": { - "version": "15.8.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-15.8.0.tgz", - "integrity": "sha512-J6ozWkaAgBh1eLdQE+C2wcXhoEgDmGJOSB6zMF5ktEtMBnU62xT3wfHcUacuTnv6rt+ollC0uZThaEpGA+sTNg==", + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-22.1.0.tgz", + "integrity": "sha512-54NdbICM7KrxsGUqQsev9aIMqPXyvyBx2218Qcm0TQ16P9CtBI+YY4hayJR6adrxlq4Ej0JLpgfUXWaQVFqmQg==", "requires": { - "comment-parser": "^0.6.1", + "comment-parser": "^0.7.2", "debug": "^4.1.1", - "flat-map-polyfill": "^0.3.8", - "jsdoctypeparser": "5.0.1", + "jsdoctypeparser": "^6.1.0", "lodash": "^4.17.15", - "object.entries-ponyfill": "^1.0.1", - "regextras": "^0.6.1" + "regextras": "^0.7.0", + "semver": "^6.3.0", + "spdx-expression-parse": "^3.0.0" }, "dependencies": { "debug": { @@ -18208,6 +20796,11 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" } } }, @@ -18228,9 +20821,9 @@ } }, "eslint-plugin-markdown": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-markdown/-/eslint-plugin-markdown-1.0.1.tgz", - "integrity": "sha512-nAUURNHJGPooBMZMP23FmTbh3LTdgoSqeFBv9FA3fYrJ+vDUJxrp6nKiQF4iDNAmnWQnmnrDvV61BmIF4X9QAQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-markdown/-/eslint-plugin-markdown-1.0.2.tgz", + "integrity": "sha512-BfvXKsO0K+zvdarNc801jsE/NTLmig4oKhZ1U3aSUgTf2dB/US5+CrfGxMsCK2Ki1vS1R3HPok+uYpufFndhzw==", "requires": { "object-assign": "^4.0.1", "remark-parse": "^5.0.0", @@ -18294,21 +20887,34 @@ } }, "eslint-plugin-react": { - "version": "7.14.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.14.3.tgz", - "integrity": "sha512-EzdyyBWC4Uz2hPYBiEJrKCUi2Fn+BJ9B/pJQcjw5X+x/H2Nm59S4MJIvL4O5NEE0+WbnQwEBxWY03oUk+Bc3FA==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.19.0.tgz", + "integrity": "sha512-SPT8j72CGuAP+JFbT0sJHOB80TX/pu44gQ4vXH/cq+hQTiY2PuZ6IHkqXJV6x1b28GDdo1lbInjKUrrdUf0LOQ==", "requires": { - "array-includes": "^3.0.3", + "array-includes": "^3.1.1", "doctrine": "^2.1.0", "has": "^1.0.3", - "jsx-ast-utils": "^2.1.0", - "object.entries": "^1.1.0", - "object.fromentries": "^2.0.0", - "object.values": "^1.1.0", + "jsx-ast-utils": "^2.2.3", + "object.entries": "^1.1.1", + "object.fromentries": "^2.0.2", + "object.values": "^1.1.1", "prop-types": "^15.7.2", - "resolve": "^1.10.1" + "resolve": "^1.15.1", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.2", + "xregexp": "^4.3.0" }, "dependencies": { + "array-includes": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", + "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0", + "is-string": "^1.0.5" + } + }, "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", @@ -18317,24 +20923,115 @@ "object-keys": "^1.0.12" } }, + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + }, + "dependencies": { + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + } + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==" + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "requires": { + "has": "^1.0.3" + } + }, + "is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==" + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "requires": { + "has-symbols": "^1.0.1" + } + }, + "jsx-ast-utils": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.2.3.tgz", + "integrity": "sha512-EdIHFMm+1BPynpKOpdPqiOsvnIrInRGJD7bzPZdPkjitQEqpdpUuFpq4T0npZFKTiB3RhWFdGN+oqOJIdhDhQA==", + "requires": { + "array-includes": "^3.0.3", + "object.assign": "^4.1.0" + } + }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==" + }, "object.entries": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.0.tgz", - "integrity": "sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.1.tgz", + "integrity": "sha512-ilqR7BgdyZetJutmDPfXCDffGa0/Yzl2ivVNpbx/g4UeWrCdRnFDUBrKJGLhGieRHDATnyZXWBeCb29k9CJysQ==", "requires": { "define-properties": "^1.1.3", - "es-abstract": "^1.12.0", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "object.fromentries": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.2.tgz", + "integrity": "sha512-r3ZiBH7MQppDJVLx6fhD618GKNG40CZYH9wgwdhKxBDDbQgjeWGGd4AtkZad84d291YxvWe7bJGuE65Anh0dxQ==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", "function-bind": "^1.1.1", "has": "^1.0.3" } }, "object.values": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz", - "integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", + "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", "requires": { "define-properties": "^1.1.3", - "es-abstract": "^1.12.0", + "es-abstract": "^1.17.0-next.1", "function-bind": "^1.1.1", "has": "^1.0.3" } @@ -18345,32 +21042,44 @@ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" }, "resolve": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", - "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", + "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", "requires": { "path-parse": "^1.0.6" } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "string.prototype.trimleft": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz", + "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimstart": "^1.0.0" + } + }, + "string.prototype.trimright": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz", + "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimend": "^1.0.0" + } } } }, "eslint-plugin-react-hooks": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.6.1.tgz", - "integrity": "sha512-wHhmGJyVuijnYIJXZJHDUF2WM+rJYTjulUTqF9k61d3BTk8etydz+M4dXUVH7M76ZRS85rqBTCx0Es/lLsrjnA==" - }, - "eslint-plugin-react-native": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-native/-/eslint-plugin-react-native-3.8.1.tgz", - "integrity": "sha512-6Z4s4nvgFRdda/1s1+uu4a6EMZwEjjJ9Bk/1yBImv0fd9U2CsGu2cUakAtV83cZKhizbWhSouXoaK4JtlScdFg==", - "requires": { - "eslint-plugin-react-native-globals": "^0.1.1" - } - }, - "eslint-plugin-react-native-globals": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-native-globals/-/eslint-plugin-react-native-globals-0.1.2.tgz", - "integrity": "sha512-9aEPf1JEpiTjcFAmmyw8eiIXmcNZOqaZyHO77wgm0/dWfT/oxC1SrIq8ET38pMxHYrcB6Uew+TzUVsBeczF88g==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-3.0.0.tgz", + "integrity": "sha512-EjxTHxjLKIBWFgDJdhKKzLh5q+vjTFrqNZX36uIxWS4OfyXe5DawqPj3U5qeJ1ngLwatjzQnmR0Lz0J0YH3kxw==" }, "eslint-scope": { "version": "4.0.3", @@ -18382,11 +21091,18 @@ } }, "eslint-utils": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.2.tgz", - "integrity": "sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.0.0.tgz", + "integrity": "sha512-0HCPuJv+7Wv1bACm8y5/ECVfYdfsAm9xmVb7saeFlxjPYALefjhbYoCkBjPdPzGH8wWyTpAez82Fh3VKYEZ8OA==", "requires": { - "eslint-visitor-keys": "^1.0.0" + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==" + } } }, "eslint-visitor-keys": { @@ -18405,16 +21121,24 @@ } }, "esprima": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", - "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=" + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true }, "esquery": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", - "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.2.0.tgz", + "integrity": "sha512-weltsSqdeWIX9G2qQZz7KlTRJdkkOCTPgLYJUz1Hacf48R4YOwGPHO3+ORfWedqJKbq5WQmsgK90n+pFLIKt/Q==", "requires": { - "estraverse": "^4.0.0" + "estraverse": "^5.0.0" + }, + "dependencies": { + "estraverse": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.0.0.tgz", + "integrity": "sha512-j3acdrMzqrxmJTNj5dbr1YbjacrYgAxVMeF0gK16E3j494mOe7xygM/ZLIguEQ0ETwAg2hlJCtHRGav+y0Ny5A==" + } } }, "esrecurse": { @@ -18501,9 +21225,9 @@ }, "dependencies": { "cross-spawn": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz", - "integrity": "sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.2.tgz", + "integrity": "sha512-PD6G8QG3S4FK/XCGFbEQrDqO2AnMMsy0meR7lerlIOHAAbkuavGU/pOqprrlvfTNjvowivTeBsjebAL0NSoMxw==", "dev": true, "requires": { "path-key": "^3.1.0", @@ -18673,39 +21397,6 @@ "jest-regex-util": "^24.9.0" }, "dependencies": { - "@jest/console": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", - "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", - "dev": true, - "requires": { - "@jest/source-map": "^24.9.0", - "chalk": "^2.0.1", - "slash": "^2.0.0" - } - }, - "@jest/source-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", - "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", - "dev": true, - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.1.15", - "source-map": "^0.6.0" - } - }, - "@jest/test-result": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", - "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", - "dev": true, - "requires": { - "@jest/console": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/istanbul-lib-coverage": "^2.0.0" - } - }, "@jest/types": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", @@ -18718,9 +21409,9 @@ } }, "@types/yargs": { - "version": "13.0.6", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.6.tgz", - "integrity": "sha512-IkltIncDQWv6fcAvnHtJ6KtkmY/vtR3bViOaCzpj/A3yNhlfZAgxNe6AEQD1cQrkYD+YsKVo08DSxvNKEsD7BA==", + "version": "13.0.8", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz", + "integrity": "sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -18732,36 +21423,17 @@ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, - "diff-sequences": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz", - "integrity": "sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==", - "dev": true - }, - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", - "dev": true - }, - "jest-diff": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.9.0.tgz", - "integrity": "sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==", + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { - "chalk": "^2.0.1", - "diff-sequences": "^24.9.0", - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, - "jest-get-type": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", - "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==", - "dev": true - }, "jest-matcher-utils": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz", @@ -18774,28 +21446,6 @@ "pretty-format": "^24.9.0" } }, - "jest-message-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", - "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/stack-utils": "^1.0.1", - "chalk": "^2.0.1", - "micromatch": "^3.1.10", - "slash": "^2.0.0", - "stack-utils": "^1.0.1" - } - }, - "jest-regex-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz", - "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==", - "dev": true - }, "pretty-format": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", @@ -18807,25 +21457,13 @@ "ansi-styles": "^3.2.0", "react-is": "^16.8.4" } - }, - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, "expect-puppeteer": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/expect-puppeteer/-/expect-puppeteer-4.3.0.tgz", - "integrity": "sha512-p8N/KSVPG9PAOJlftK5f1n3JrULJ6Qq1EQ8r/n9xzkX2NmXbK8PcnJnkSAEzEHrMycELKGnlJV7M5nkgm+wEWA==" + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/expect-puppeteer/-/expect-puppeteer-4.4.0.tgz", + "integrity": "sha512-6Ey4Xy2xvmuQu7z7YQtMsaMV0EHJRpVxIDOd5GRrm04/I3nkTKIutELfECsLp6le+b3SSa3cXhPiw6PgqzxYWA==" }, "express": { "version": "4.17.1", @@ -19093,6 +21731,7 @@ "version": "1.6.7", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.7.tgz", "integrity": "sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k=", + "dev": true, "requires": { "concat-stream": "1.6.2", "debug": "2.6.9", @@ -19104,6 +21743,7 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, "requires": { "ms": "2.0.0" } @@ -19131,6 +21771,11 @@ "resolved": "https://registry.npmjs.org/fast-average-color/-/fast-average-color-4.3.0.tgz", "integrity": "sha512-k8FXd6+JeXoItmdNqB3hMwFgArryjdYBLuzEM8fRY/oztd/051yhSHU6GUrMOfIQU9dDHyFDcIAkGrQKlYtpDA==" }, + "fast-base64-decode": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-base64-decode/-/fast-base64-decode-1.0.0.tgz", + "integrity": "sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q==" + }, "fast-deep-equal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", @@ -19261,6 +21906,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", + "dev": true, "requires": { "pend": "~1.2.0" } @@ -19361,12 +22007,24 @@ "klaw": "^1.0.0", "path-is-absolute": "^1.0.0", "rimraf": "^2.2.8" + }, + "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } } }, "glob": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -19504,15 +22162,25 @@ } }, "find-process": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/find-process/-/find-process-1.4.2.tgz", - "integrity": "sha512-O83EVJr4dWvHJ7QpUzANNAMeQVKukRzRqRx4AIzdLYRrQorRdbqDwLPigkd9PYPhJRhmNPAoVjOm9bcwSmcZaw==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/find-process/-/find-process-1.4.3.tgz", + "integrity": "sha512-+IA+AUsQCf3uucawyTwMWcY+2M3FXq3BRvw3S+j5Jvydjk31f/+NPWpYZOJs+JUs2GvxH4Yfr6Wham0ZtRLlPA==", "requires": { "chalk": "^2.0.1", "commander": "^2.11.0", "debug": "^2.6.8" }, "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, "commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -19671,11 +22339,6 @@ } } }, - "flat-map-polyfill": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/flat-map-polyfill/-/flat-map-polyfill-0.3.8.tgz", - "integrity": "sha512-ZfmD5MnU7GglUEhiky9C7yEPaNq1/wh36RDohe+Xr3nJVdccwHbdTkFIYvetcdsoAckUKT51fuf44g7Ni5Doyg==" - }, "flatted": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.0.tgz", @@ -19741,6 +22404,17 @@ "worker-rpc": "^0.1.0" }, "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -19861,6 +22535,20 @@ "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==", "optional": true }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "optional": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, "minipass": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", @@ -19887,6 +22575,17 @@ "rimraf": "^2.6.1", "semver": "^5.3.0", "tar": "^4" + }, + "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "optional": true, + "requires": { + "glob": "^7.1.3" + } + } } }, "nopt": { @@ -19944,6 +22643,7 @@ "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -19952,6 +22652,15 @@ "once": "^1.3.0", "path-is-absolute": "^1.0.0" } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } } } }, @@ -19975,6 +22684,11 @@ "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=" }, + "functions-have-names": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.1.tgz", + "integrity": "sha512-j48B/ZI7VKs3sgeI2cZp7WXWmZXu7Iq5pl5/vptV5N2mq+DGFuS/ulaDjtaoLpYzuD6u8UgrUKHfgo7fDTSiBA==" + }, "fuse.js": { "version": "3.4.6", "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-3.4.6.tgz", @@ -20645,6 +23359,52 @@ "delegate": "^3.1.2" } }, + "got": { + "version": "10.7.0", + "resolved": "https://registry.npmjs.org/got/-/got-10.7.0.tgz", + "integrity": "sha512-aWTDeNw9g+XqEZNcTjMMZSy7B7yE9toWOFYip7ofFTLleJhvZwUxxTxkTpKvF+p1SAA4VHmuEy7PiHTHyq8tJg==", + "requires": { + "@sindresorhus/is": "^2.0.0", + "@szmarczak/http-timer": "^4.0.0", + "@types/cacheable-request": "^6.0.1", + "cacheable-lookup": "^2.0.0", + "cacheable-request": "^7.0.1", + "decompress-response": "^5.0.0", + "duplexer3": "^0.1.4", + "get-stream": "^5.0.0", + "lowercase-keys": "^2.0.0", + "mimic-response": "^2.1.0", + "p-cancelable": "^2.0.0", + "p-event": "^4.0.0", + "responselike": "^2.0.0", + "to-readable-stream": "^2.0.0", + "type-fest": "^0.10.0" + }, + "dependencies": { + "get-stream": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", + "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "requires": { + "pump": "^3.0.0" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "type-fest": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.10.0.tgz", + "integrity": "sha512-EUV9jo4sffrwlg8s0zDhP0T2WD3pru5Xi0+HTE3zTUmBaZNhfkite9PdSJwdXLwPVW0jnAHT56pZHIOYckPEiw==" + } + } + }, "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", @@ -20691,6 +23451,7 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.4.0.tgz", "integrity": "sha512-xkRtOt3/3DzTKMOt3xahj2M/EqNhY988T+imYSlMgs5fVhLN2fmKVVj0LtEGmb+3UUYV5Qmm1052Mm3dIQxOvw==", + "dev": true, "requires": { "neo-async": "^2.6.0", "optimist": "^0.6.1", @@ -20701,12 +23462,14 @@ "neo-async": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", - "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==" + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", + "dev": true }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true } } }, @@ -20724,6 +23487,11 @@ "har-schema": "^2.0.0" } }, + "hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==" + }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -20996,9 +23764,9 @@ "dev": true }, "html-element-map": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/html-element-map/-/html-element-map-1.0.0.tgz", - "integrity": "sha512-/SP6aOiM5Ai9zALvCxDubIeez0LvG3qP7R9GcRDnJEP/HBmv0A8A9K0o8+HFudcFt46+i921ANjzKsjPjb7Enw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/html-element-map/-/html-element-map-1.2.0.tgz", + "integrity": "sha512-0uXq8HsuG1v2TmQ8QkIhzbrqeskE4kn52Q18QJ9iAA/SnHoEKXWiUxHQtclRsCFWEUD2So34X+0+pZZu862nnw==", "requires": { "array-filter": "^1.0.0" } @@ -21017,6 +23785,11 @@ "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=", "dev": true }, + "html-escaper": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.0.tgz", + "integrity": "sha512-a4u9BeERWGu/S8JiWEAQcdrg9v4QArtP9keViQjGMdff20fBdd8waotXaNmODqBe6uZ3Nafi7K/ho4gCQHV3Ig==" + }, "html-minifier-terser": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-5.0.2.tgz", @@ -21186,8 +23959,7 @@ "human-signals": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", - "dev": true + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==" }, "humanize-ms": { "version": "1.2.1", @@ -21217,6 +23989,17 @@ "slash": "^3.0.0" }, "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, "cosmiconfig": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", @@ -21459,6 +24242,30 @@ "chalk": "^2.4.2", "source-map": "^0.6.1", "supports-color": "^6.1.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + } } }, "source-map": { @@ -21690,88 +24497,114 @@ "dev": true }, "inquirer": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.3.tgz", - "integrity": "sha512-+OiOVeVydu4hnCGLCSX+wedovR/Yzskv9BFqUNNKq9uU2qg7LCcCo3R86S2E7WLo0y/x2pnEZfZe1CoYnORUAw==", - "dev": true, + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.1.0.tgz", + "integrity": "sha512-5fJMWEmikSYu0nv/flMc475MhGbB7TSPd/2IpFV4I4rMklboCH2rQjYY5kKiYGHqUF9gvaambupcJFFG9dvReg==", "requires": { "ansi-escapes": "^4.2.1", - "chalk": "^2.4.2", + "chalk": "^3.0.0", "cli-cursor": "^3.1.0", "cli-width": "^2.0.0", "external-editor": "^3.0.3", "figures": "^3.0.0", "lodash": "^4.17.15", "mute-stream": "0.0.8", - "run-async": "^2.2.0", + "run-async": "^2.4.0", "rxjs": "^6.5.3", "string-width": "^4.1.0", - "strip-ansi": "^5.1.0", + "strip-ansi": "^6.0.0", "through": "^2.3.6" }, "dependencies": { "ansi-escapes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.0.tgz", - "integrity": "sha512-EiYhwo0v255HUL6eDyuLrXEkTi7WwVCLAw+SeOQ7M7qdun1z1pum4DEm/nuqIVbPvi9RPPc9k9LbyBv6H0DwVg==", - "dev": true, + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", + "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", "requires": { - "type-fest": "^0.8.1" + "type-fest": "^0.11.0" } }, "ansi-regex": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + }, + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } }, "cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, "requires": { "restore-cursor": "^3.1.0" } }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "figures": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.1.0.tgz", - "integrity": "sha512-ravh8VRXqHuMvZt/d8GblBeqDMkdJMBdv/2KntFH+ra5MXkO7nxNKpzQ3n6QD/2da1kH0aWmNISdvhM7gl2gVg==", - "dev": true, + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", "requires": { "escape-string-regexp": "^1.0.5" } }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" }, "mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" }, "mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, "onetime": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", - "dev": true, "requires": { "mimic-fn": "^2.1.0" } @@ -21780,17 +24613,23 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, "requires": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" } }, + "run-async": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.0.tgz", + "integrity": "sha512-xJTbh/d7Lm7SBhc1tNvTpeCHaEzoyxPrqNlvSdMfBTYwaY++UJFyXUOxAtsRUXjlqOfj8luNaR9vjCh4KeV+pg==", + "requires": { + "is-promise": "^2.1.0" + } + }, "rxjs": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz", - "integrity": "sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==", - "dev": true, + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.5.tgz", + "integrity": "sha512-WfQI+1gohdf0Dai/Bbmk5L5ItH5tYqm3ki2c5GdWhKjalzjg93N3avFjVStyZZz+A2Em+ZxKH5bNghw9UeylGQ==", "requires": { "tslib": "^1.9.0" } @@ -21799,46 +24638,32 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", - "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.0" - }, - "dependencies": { - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - } } }, "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", "requires": { - "ansi-regex": "^4.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - } + "ansi-regex": "^5.0.0" + } + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "requires": { + "has-flag": "^4.0.0" } }, "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", + "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==" } } }, @@ -21846,7 +24671,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.2.tgz", "integrity": "sha512-2cQNfwhAfJIkU4KZPkDI+Gj5yNNnbqi40W9Gge6dfnk4TocEVm00B3bdiL+JINrbGJil2TeHvM4rETGzk/f/0g==", - "dev": true, "requires": { "es-abstract": "^1.17.0-next.1", "has": "^1.0.3", @@ -21857,7 +24681,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, "requires": { "object-keys": "^1.0.12" } @@ -21866,7 +24689,6 @@ "version": "1.17.4", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz", "integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==", - "dev": true, "requires": { "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", @@ -21885,7 +24707,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, "requires": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -21895,20 +24716,17 @@ "has-symbols": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" }, "is-callable": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", - "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", - "dev": true + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==" }, "is-regex": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", - "dev": true, "requires": { "has": "^1.0.3" } @@ -21917,7 +24735,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "dev": true, "requires": { "has-symbols": "^1.0.1" } @@ -21925,20 +24742,17 @@ "object-inspect": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", - "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", - "dev": true + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==" }, "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" }, "string.prototype.trimleft": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", - "dev": true, "requires": { "define-properties": "^1.1.3", "function-bind": "^1.1.1" @@ -21948,7 +24762,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", - "dev": true, "requires": { "define-properties": "^1.1.3", "function-bind": "^1.1.1" @@ -21981,16 +24794,16 @@ "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", "dev": true }, + "ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=" + }, "ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" }, - "irregular-plurals": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-2.0.0.tgz", - "integrity": "sha512-Y75zBYLkh0lJ9qxeHlMjQ7bSbyiSqNW/UOPWDmzC7cXskL1hekSITh1Oc6JV0XCWWZ9DE8VYSB71xocLk3gmGw==" - }, "is-absolute-url": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", @@ -22054,9 +24867,9 @@ } }, "is-boolean-object": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.0.0.tgz", - "integrity": "sha1-mPiygDBoQhmpXzdc+9iM40Bd/5M=" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.0.1.tgz", + "integrity": "sha512-TqZuVwa/sppcrhUCAYkGBk7w0yxfQQnxq28fjkO53tnK9FQXmdwz2JS5+GjsWQ6RByES1K40nI+yDic5c9/aAQ==" }, "is-buffer": { "version": "1.1.6", @@ -22206,9 +25019,9 @@ "dev": true }, "is-generator-fn": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.0.0.tgz", - "integrity": "sha512-elzyIdM7iKoFHzcrndIqjYomImhxrFRnGP3galODoII4TB9gI7mZ+FnlLQmmjf27SxHS2gKEeyhX5/+YRS6H9g==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==" }, "is-glob": { "version": "4.0.0", @@ -22254,9 +25067,9 @@ } }, "is-number-object": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.3.tgz", - "integrity": "sha1-8mWrian0RQNO9q/xWo8AsA9VF5k=" + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz", + "integrity": "sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==" }, "is-obj": { "version": "1.0.1", @@ -22350,7 +25163,8 @@ "is-string": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.4.tgz", - "integrity": "sha1-zDqbaYV9Yh6WNyWiTK7shzuCbmQ=" + "integrity": "sha1-zDqbaYV9Yh6WNyWiTK7shzuCbmQ=", + "dev": true }, "is-subset": { "version": "0.1.1", @@ -22401,9 +25215,9 @@ "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" }, "is-whitespace-character": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.2.tgz", - "integrity": "sha512-SzM+T5GKUCtLhlHFKt2SDAX2RFzfS6joT91F2/WSi9LxgFdsnhfPK/UIA+JhRR2xuyLdrCys2PiFDrtn1fU5hQ==" + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz", + "integrity": "sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==" }, "is-windows": { "version": "1.0.2", @@ -22411,9 +25225,9 @@ "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" }, "is-word-character": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.2.tgz", - "integrity": "sha512-T3FlsX8rCHAH8e7RE7PfOPZVFQlcV3XRF9eOOBQ1uf70OxO7CjjSOjeImMPCADBdYWcStAbVbYvJ1m2D3tb+EA==" + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.4.tgz", + "integrity": "sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==" }, "is-wsl": { "version": "1.1.0", @@ -22461,73 +25275,63 @@ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, "istanbul-lib-coverage": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", - "integrity": "sha512-dKWuzRGCs4G+67VfW9pBFFz2Jpi4vSp/k7zBcJ888ofV5Mi1g5CUML5GvMvV6u9Cjybftu+E8Cgp+k0dI1E5lw==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", + "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==" }, "istanbul-lib-instrument": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.1.0.tgz", - "integrity": "sha512-ooVllVGT38HIk8MxDj/OIHXSYvH+1tq/Vb38s8ixt9GoJadXska4WkGY+0wkmtYCZNYtaARniH/DixUGGLZ0uA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.1.tgz", + "integrity": "sha512-imIchxnodll7pvQBYOqUu88EufLCU56LMeFPZZM/fJZ1irYcYdqroaV+ACK1Ila8ls09iEYArp+nqyC6lW1Vfg==", "requires": { - "@babel/generator": "^7.0.0", - "@babel/parser": "^7.0.0", - "@babel/template": "^7.0.0", - "@babel/traverse": "^7.0.0", - "@babel/types": "^7.0.0", - "istanbul-lib-coverage": "^2.0.3", - "semver": "^5.5.0" + "@babel/core": "^7.7.5", + "@babel/parser": "^7.7.5", + "@babel/template": "^7.7.4", + "@babel/traverse": "^7.7.4", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" }, "dependencies": { "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" } } }, "istanbul-lib-report": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.4.tgz", - "integrity": "sha512-sOiLZLAWpA0+3b5w5/dq0cjm2rrNdAfHWaGhmn7XEFW6X++IV9Ohn+pnELAl9K3rfpaeBfbmH9JU5sejacdLeA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", "requires": { - "istanbul-lib-coverage": "^2.0.3", - "make-dir": "^1.3.0", - "supports-color": "^6.0.0" + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" }, "dependencies": { - "make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", - "requires": { - "pify": "^3.0.0" - } - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" } } } }, "istanbul-lib-source-maps": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.2.tgz", - "integrity": "sha512-JX4v0CiKTGp9fZPmoxpu9YEkPbEqCqBbO3403VabKjH+NRXo72HafD5UgnjTEqHL2SAjaZK1XDuDOkn6I5QVfQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", + "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", "requires": { "debug": "^4.1.1", - "istanbul-lib-coverage": "^2.0.3", - "make-dir": "^1.3.0", - "rimraf": "^2.6.2", + "istanbul-lib-coverage": "^3.0.0", "source-map": "^0.6.1" }, "dependencies": { @@ -22539,24 +25343,11 @@ "ms": "^2.1.1" } }, - "make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", - "requires": { - "pify": "^3.0.0" - } - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" - }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -22564,6 +25355,15 @@ } } }, + "istanbul-reports": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.7.tgz", + "integrity": "sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0" + } + }, "iterate-iterator": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.1.tgz", @@ -22589,55 +25389,17 @@ "version": "24.9.0", "resolved": "https://registry.npmjs.org/jest/-/jest-24.9.0.tgz", "integrity": "sha512-YvkBL1Zm7d2B1+h5fHEOdyjCG+sGMz4f8D86/0HiqJ6MB4MnDc8FgP5vdWsGnemOQro7lnYo8UakZ3+5A0jxGw==", + "dev": true, "requires": { "import-local": "^2.0.0", "jest-cli": "^24.9.0" }, "dependencies": { - "@jest/console": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", - "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", - "requires": { - "@jest/source-map": "^24.9.0", - "chalk": "^2.0.1", - "slash": "^2.0.0" - } - }, - "@jest/fake-timers": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz", - "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", - "requires": { - "@jest/types": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-mock": "^24.9.0" - } - }, - "@jest/source-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", - "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.1.15", - "source-map": "^0.6.0" - } - }, - "@jest/test-result": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", - "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", - "requires": { - "@jest/console": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/istanbul-lib-coverage": "^2.0.0" - } - }, "@jest/types": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^1.1.1", @@ -22645,9 +25407,10 @@ } }, "@types/yargs": { - "version": "13.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.4.tgz", - "integrity": "sha512-Ke1WmBbIkVM8bpvsNEcGgQM70XcEh/nbpxQhW7FhrsbCsXSY9BmLB1+LHtD7r9zrsOcFlLiF+a/UeJsdfw3C5A==", + "version": "13.0.8", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz", + "integrity": "sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA==", + "dev": true, "requires": { "@types/yargs-parser": "*" } @@ -22655,17 +25418,31 @@ "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true }, "camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } }, "cliui": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, "requires": { "string-width": "^3.1.0", "strip-ansi": "^5.2.0", @@ -22676,6 +25453,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, "requires": { "locate-path": "^3.0.0" } @@ -22683,17 +25461,14 @@ "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" - }, - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true }, "jest-cli": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-24.9.0.tgz", "integrity": "sha512-+VLRKyitT3BWoMeSUIHRxV/2g8y9gw91Jh5z2UmXZzkZKpbC08CSehVxgHUwTpy+HwGcns/tqafQDJW7imYvGg==", + "dev": true, "requires": { "@jest/core": "^24.9.0", "@jest/test-result": "^24.9.0", @@ -22710,84 +25485,21 @@ "yargs": "^13.3.0" } }, - "jest-get-type": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", - "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==" - }, - "jest-message-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", - "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", - "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/stack-utils": "^1.0.1", - "chalk": "^2.0.1", - "micromatch": "^3.1.10", - "slash": "^2.0.0", - "stack-utils": "^1.0.1" - } - }, - "jest-mock": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz", - "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", - "requires": { - "@jest/types": "^24.9.0" - } - }, - "jest-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz", - "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", - "requires": { - "@jest/console": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/source-map": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "callsites": "^3.0.0", - "chalk": "^2.0.1", - "graceful-fs": "^4.1.15", - "is-ci": "^2.0.0", - "mkdirp": "^0.5.1", - "slash": "^2.0.0", - "source-map": "^0.6.0" - } - }, - "jest-validate": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.9.0.tgz", - "integrity": "sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ==", - "requires": { - "@jest/types": "^24.9.0", - "camelcase": "^5.3.1", - "chalk": "^2.0.1", - "jest-get-type": "^24.9.0", - "leven": "^3.1.0", - "pretty-format": "^24.9.0" - } - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" - }, "locate-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, "requires": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, "requires": { "p-try": "^2.0.0" } @@ -22796,45 +25508,28 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, "requires": { "p-limit": "^2.0.0" } }, "p-try": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" - }, - "pretty-format": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", - "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", - "requires": { - "@jest/types": "^24.9.0", - "ansi-regex": "^4.0.0", - "ansi-styles": "^3.2.0", - "react-is": "^16.8.4" - } + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true }, "require-main-filename": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" - }, - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, "requires": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", @@ -22845,6 +25540,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, "requires": { "ansi-regex": "^4.1.0" } @@ -22853,6 +25549,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, "requires": { "ansi-styles": "^3.2.0", "string-width": "^3.0.0", @@ -22862,12 +25559,14 @@ "y18n": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true }, "yargs": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", - "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, "requires": { "cliui": "^5.0.0", "find-up": "^3.0.0", @@ -22878,7 +25577,17 @@ "string-width": "^3.0.0", "which-module": "^2.0.0", "y18n": "^4.0.0", - "yargs-parser": "^13.1.1" + "yargs-parser": "^13.1.2" + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" } } } @@ -22887,6 +25596,7 @@ "version": "24.9.0", "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-24.9.0.tgz", "integrity": "sha512-6aTWpe2mHF0DhL28WjdkO8LyGjs3zItPET4bMSeXU6T3ub4FPMw+mcOcbdGXQOAfmLcxofD23/5Bl9Z4AkFwqg==", + "dev": true, "requires": { "@jest/types": "^24.9.0", "execa": "^1.0.0", @@ -22897,6 +25607,7 @@ "version": "24.9.0", "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^1.1.1", @@ -22904,9 +25615,10 @@ } }, "@types/yargs": { - "version": "13.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.4.tgz", - "integrity": "sha512-Ke1WmBbIkVM8bpvsNEcGgQM70XcEh/nbpxQhW7FhrsbCsXSY9BmLB1+LHtD7r9zrsOcFlLiF+a/UeJsdfw3C5A==", + "version": "13.0.8", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz", + "integrity": "sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA==", + "dev": true, "requires": { "@types/yargs-parser": "*" } @@ -22915,6 +25627,7 @@ "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, "requires": { "nice-try": "^1.0.4", "path-key": "^2.0.1", @@ -22927,6 +25640,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, "requires": { "cross-spawn": "^6.0.0", "get-stream": "^4.0.0", @@ -22941,6 +25655,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, "requires": { "pump": "^3.0.0" } @@ -22949,6 +25664,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -22957,7 +25673,8 @@ "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true } } }, @@ -22965,6 +25682,7 @@ "version": "24.9.0", "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.9.0.tgz", "integrity": "sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ==", + "dev": true, "requires": { "@babel/core": "^7.1.0", "@jest/test-sequencer": "^24.9.0", @@ -22985,50 +25703,11 @@ "realpath-native": "^1.1.0" }, "dependencies": { - "@jest/console": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", - "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", - "requires": { - "@jest/source-map": "^24.9.0", - "chalk": "^2.0.1", - "slash": "^2.0.0" - } - }, - "@jest/fake-timers": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz", - "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", - "requires": { - "@jest/types": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-mock": "^24.9.0" - } - }, - "@jest/source-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", - "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.1.15", - "source-map": "^0.6.0" - } - }, - "@jest/test-result": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", - "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", - "requires": { - "@jest/console": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/istanbul-lib-coverage": "^2.0.0" - } - }, "@jest/types": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^1.1.1", @@ -23036,9 +25715,10 @@ } }, "@types/yargs": { - "version": "13.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.4.tgz", - "integrity": "sha512-Ke1WmBbIkVM8bpvsNEcGgQM70XcEh/nbpxQhW7FhrsbCsXSY9BmLB1+LHtD7r9zrsOcFlLiF+a/UeJsdfw3C5A==", + "version": "13.0.8", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz", + "integrity": "sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA==", + "dev": true, "requires": { "@types/yargs-parser": "*" } @@ -23046,150 +25726,91 @@ "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" - }, - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" - }, - "jest-get-type": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", - "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==" - }, - "jest-message-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", - "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", - "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/stack-utils": "^1.0.1", - "chalk": "^2.0.1", - "micromatch": "^3.1.10", - "slash": "^2.0.0", - "stack-utils": "^1.0.1" - } - }, - "jest-mock": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz", - "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", - "requires": { - "@jest/types": "^24.9.0" - } - }, - "jest-resolve": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.9.0.tgz", - "integrity": "sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ==", - "requires": { - "@jest/types": "^24.9.0", - "browser-resolve": "^1.11.3", - "chalk": "^2.0.1", - "jest-pnp-resolver": "^1.2.1", - "realpath-native": "^1.1.0" - } - }, - "jest-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz", - "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", - "requires": { - "@jest/console": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/source-map": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "callsites": "^3.0.0", - "chalk": "^2.0.1", - "graceful-fs": "^4.1.15", - "is-ci": "^2.0.0", - "mkdirp": "^0.5.1", - "slash": "^2.0.0", - "source-map": "^0.6.0" - } + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true }, - "jest-validate": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.9.0.tgz", - "integrity": "sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ==", + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, "requires": { - "@jest/types": "^24.9.0", - "camelcase": "^5.3.1", - "chalk": "^2.0.1", - "jest-get-type": "^24.9.0", - "leven": "^3.1.0", - "pretty-format": "^24.9.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" - }, "pretty-format": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", + "dev": true, "requires": { "@jest/types": "^24.9.0", "ansi-regex": "^4.0.0", "ansi-styles": "^3.2.0", "react-is": "^16.8.4" } - }, - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" } } }, "jest-dev-server": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/jest-dev-server/-/jest-dev-server-4.3.0.tgz", - "integrity": "sha512-bC9flKY2G1honQ/UI0gEhb0wFnDhpFr7xidC8Nk+evi7TgnNtfsGIzzF2dcIhF1G9BGF0n/M7CJrMAzwQhyTPA==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/jest-dev-server/-/jest-dev-server-4.4.0.tgz", + "integrity": "sha512-STEHJ3iPSC8HbrQ3TME0ozGX2KT28lbT4XopPxUm2WimsX3fcB3YOptRh12YphQisMhfqNSNTZUmWyT3HEXS2A==", "requires": { - "chalk": "^2.4.2", + "chalk": "^3.0.0", "cwd": "^0.10.0", - "find-process": "^1.4.2", - "prompts": "^2.1.0", - "spawnd": "^4.0.0", - "tree-kill": "^1.2.1", + "find-process": "^1.4.3", + "prompts": "^2.3.0", + "spawnd": "^4.4.0", + "tree-kill": "^1.2.2", "wait-on": "^3.3.0" }, "dependencies": { - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } }, - "prompts": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.3.0.tgz", - "integrity": "sha512-NfbbPPg/74fT7wk2XYQ7hAIp9zJyZp5Fu19iRbORqqy1BhtrkZ0fPafBU+7bmn8ie69DpT0R6QpJIN2oisYjJg==", + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.3" + "color-name": "~1.1.4" } }, - "sisteransi": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.4.tgz", - "integrity": "sha512-/ekMoM4NJ59ivGSfKapeG+FWtrmWvA1p6FBZwXrqojw90vJu8lBmrTxCMuBCydKtkaUe2zt4PlxeTKpjwMbyig==" + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "requires": { + "has-flag": "^4.0.0" + } }, "tree-kill": { "version": "1.2.2", @@ -23199,80 +25820,95 @@ } }, "jest-diff": { - "version": "24.7.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.7.0.tgz", - "integrity": "sha512-ULQZ5B1lWpH70O4xsANC4tf4Ko6RrpwhE3PtG6ERjMg1TiYTC2Wp4IntJVGro6a8HG9luYHhhmF4grF0Pltckg==", - "requires": { - "chalk": "^2.0.1", - "diff-sequences": "^24.3.0", - "jest-get-type": "^24.3.0", - "pretty-format": "^24.7.0" - } - }, - "jest-docblock": { - "version": "24.3.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-24.3.0.tgz", - "integrity": "sha512-nlANmF9Yq1dufhFlKG9rasfQlrY7wINJbo3q01tu56Jv5eBU5jirylhF2O5ZBnLxzOVBGRDz/9NAwNyBtG4Nyg==", - "requires": { - "detect-newline": "^2.1.0" - } - }, - "jest-each": { "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-24.9.0.tgz", - "integrity": "sha512-ONi0R4BvW45cw8s2Lrx8YgbeXL1oCQ/wIDwmsM3CqM/nlblNCPmnC3IPQlMbRFZu3wKdQ2U8BqM6lh3LJ5Bsog==", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.9.0.tgz", + "integrity": "sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==", + "dev": true, "requires": { - "@jest/types": "^24.9.0", "chalk": "^2.0.1", + "diff-sequences": "^24.9.0", "jest-get-type": "^24.9.0", - "jest-util": "^24.9.0", "pretty-format": "^24.9.0" }, "dependencies": { - "@jest/console": { + "@jest/types": { "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", - "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, "requires": { - "@jest/source-map": "^24.9.0", - "chalk": "^2.0.1", - "slash": "^2.0.0" + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" } }, - "@jest/fake-timers": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz", - "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", + "@types/yargs": { + "version": "13.0.8", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz", + "integrity": "sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA==", + "dev": true, "requires": { - "@jest/types": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-mock": "^24.9.0" + "@types/yargs-parser": "*" } }, - "@jest/source-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", - "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.1.15", - "source-map": "^0.6.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, - "@jest/test-result": { + "pretty-format": { "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", - "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", + "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", + "dev": true, "requires": { - "@jest/console": "^24.9.0", "@jest/types": "^24.9.0", - "@types/istanbul-lib-coverage": "^2.0.0" + "ansi-regex": "^4.0.0", + "ansi-styles": "^3.2.0", + "react-is": "^16.8.4" } - }, + } + } + }, + "jest-docblock": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-24.9.0.tgz", + "integrity": "sha512-F1DjdpDMJMA1cN6He0FNYNZlo3yYmOtRUnktrT9Q37njYzC5WEaDdmbynIgy0L/IvXvvgsG8OsqhLPXTpfmZAA==", + "dev": true, + "requires": { + "detect-newline": "^2.1.0" + } + }, + "jest-each": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-24.9.0.tgz", + "integrity": "sha512-ONi0R4BvW45cw8s2Lrx8YgbeXL1oCQ/wIDwmsM3CqM/nlblNCPmnC3IPQlMbRFZu3wKdQ2U8BqM6lh3LJ5Bsog==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "jest-get-type": "^24.9.0", + "jest-util": "^24.9.0", + "pretty-format": "^24.9.0" + }, + "dependencies": { "@jest/types": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^1.1.1", @@ -23280,9 +25916,10 @@ } }, "@types/yargs": { - "version": "13.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.4.tgz", - "integrity": "sha512-Ke1WmBbIkVM8bpvsNEcGgQM70XcEh/nbpxQhW7FhrsbCsXSY9BmLB1+LHtD7r9zrsOcFlLiF+a/UeJsdfw3C5A==", + "version": "13.0.8", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz", + "integrity": "sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA==", + "dev": true, "requires": { "@types/yargs-parser": "*" } @@ -23290,87 +25927,38 @@ "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" - }, - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" - }, - "jest-get-type": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", - "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==" - }, - "jest-message-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", - "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", - "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/stack-utils": "^1.0.1", - "chalk": "^2.0.1", - "micromatch": "^3.1.10", - "slash": "^2.0.0", - "stack-utils": "^1.0.1" - } - }, - "jest-mock": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz", - "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", - "requires": { - "@jest/types": "^24.9.0" - } + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true }, - "jest-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz", - "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, "requires": { - "@jest/console": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/source-map": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "callsites": "^3.0.0", - "chalk": "^2.0.1", - "graceful-fs": "^4.1.15", - "is-ci": "^2.0.0", - "mkdirp": "^0.5.1", - "slash": "^2.0.0", - "source-map": "^0.6.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, "pretty-format": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", + "dev": true, "requires": { "@jest/types": "^24.9.0", "ansi-regex": "^4.0.0", "ansi-styles": "^3.2.0", "react-is": "^16.8.4" } - }, - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" } } }, "jest-emotion": { - "version": "10.0.17", - "resolved": "https://registry.npmjs.org/jest-emotion/-/jest-emotion-10.0.17.tgz", - "integrity": "sha512-Z0SqaeXGr9dshhY5z9ctfPiw2qTw5BRbCsbBWziTtSdiLnqFprj2NuF38lMrpSMFKjNY+q+rioRI5gVyQZrrxA==", + "version": "10.0.32", + "resolved": "https://registry.npmjs.org/jest-emotion/-/jest-emotion-10.0.32.tgz", + "integrity": "sha512-hW3IwWc47qRuxnGsWFGY6uIMX8F4YBzq+Qci3LAYUCUqUBNP+1DU1L5Nudo9Ry0NHVFOqDnDeip1p2UR0kVMwA==", "dev": true, "requires": { "@babel/runtime": "^7.5.5", @@ -23379,20 +25967,22 @@ "css": "^2.2.1" }, "dependencies": { - "@babel/runtime": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.8.3.tgz", - "integrity": "sha512-fVHx1rzEmwB130VTkLnxR+HmxcTjGzH12LYQcFFoBwakMd3aOMD4OsRN7tGG/UOYE2ektgFrS8uACAoRk1CY0w==", - "dev": true, - "requires": { - "regenerator-runtime": "^0.13.2" - } - }, "@types/jest": { "version": "23.3.14", "resolved": "https://registry.npmjs.org/@types/jest/-/jest-23.3.14.tgz", "integrity": "sha512-Q5hTcfdudEL2yOmluA1zaSyPbzWPmJ3XfSWeP3RyoYvS9hnje1ZyagrZOuQ6+1nQC1Gw+7gap3pLNL3xL6UBug==", "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } } } }, @@ -23400,6 +25990,7 @@ "version": "24.9.0", "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-24.9.0.tgz", "integrity": "sha512-Zv9FV9NBRzLuALXjvRijO2351DRQeLYXtpD4xNvfoVFw21IOKNhZAEUKcbiEtjTkm2GsJ3boMVgkaR7rN8qetA==", + "dev": true, "requires": { "@jest/environment": "^24.9.0", "@jest/fake-timers": "^24.9.0", @@ -23409,50 +26000,11 @@ "jsdom": "^11.5.1" }, "dependencies": { - "@jest/console": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", - "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", - "requires": { - "@jest/source-map": "^24.9.0", - "chalk": "^2.0.1", - "slash": "^2.0.0" - } - }, - "@jest/fake-timers": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz", - "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", - "requires": { - "@jest/types": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-mock": "^24.9.0" - } - }, - "@jest/source-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", - "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.1.15", - "source-map": "^0.6.0" - } - }, - "@jest/test-result": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", - "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", - "requires": { - "@jest/console": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/istanbul-lib-coverage": "^2.0.0" - } - }, "@jest/types": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^1.1.1", @@ -23460,69 +26012,71 @@ } }, "@types/yargs": { - "version": "13.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.4.tgz", - "integrity": "sha512-Ke1WmBbIkVM8bpvsNEcGgQM70XcEh/nbpxQhW7FhrsbCsXSY9BmLB1+LHtD7r9zrsOcFlLiF+a/UeJsdfw3C5A==", + "version": "13.0.8", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz", + "integrity": "sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA==", + "dev": true, "requires": { "@types/yargs-parser": "*" } }, - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" - }, - "jest-message-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", - "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", + "cssstyle": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.4.0.tgz", + "integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==", + "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/stack-utils": "^1.0.1", - "chalk": "^2.0.1", - "micromatch": "^3.1.10", - "slash": "^2.0.0", - "stack-utils": "^1.0.1" + "cssom": "0.3.x" } }, - "jest-mock": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz", - "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", - "requires": { - "@jest/types": "^24.9.0" + "jsdom": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", + "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", + "dev": true, + "requires": { + "abab": "^2.0.0", + "acorn": "^5.5.3", + "acorn-globals": "^4.1.0", + "array-equal": "^1.0.0", + "cssom": ">= 0.3.2 < 0.4.0", + "cssstyle": "^1.0.0", + "data-urls": "^1.0.0", + "domexception": "^1.0.1", + "escodegen": "^1.9.1", + "html-encoding-sniffer": "^1.0.2", + "left-pad": "^1.3.0", + "nwsapi": "^2.0.7", + "parse5": "4.0.0", + "pn": "^1.1.0", + "request": "^2.87.0", + "request-promise-native": "^1.0.5", + "sax": "^1.2.4", + "symbol-tree": "^3.2.2", + "tough-cookie": "^2.3.4", + "w3c-hr-time": "^1.0.1", + "webidl-conversions": "^4.0.2", + "whatwg-encoding": "^1.0.3", + "whatwg-mimetype": "^2.1.0", + "whatwg-url": "^6.4.1", + "ws": "^5.2.0", + "xml-name-validator": "^3.0.0" } }, - "jest-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz", - "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", + "parse5": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", + "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", + "dev": true + }, + "ws": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", + "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", + "dev": true, "requires": { - "@jest/console": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/source-map": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "callsites": "^3.0.0", - "chalk": "^2.0.1", - "graceful-fs": "^4.1.15", - "is-ci": "^2.0.0", - "mkdirp": "^0.5.1", - "slash": "^2.0.0", - "source-map": "^0.6.0" + "async-limiter": "~1.0.0" } - }, - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" } } }, @@ -23530,6 +26084,7 @@ "version": "24.9.0", "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-24.9.0.tgz", "integrity": "sha512-6d4V2f4nxzIzwendo27Tr0aFm+IXWa0XEUnaH6nU0FMaozxovt+sfRvh4J47wL1OvF83I3SSTu0XK+i4Bqe7uA==", + "dev": true, "requires": { "@jest/environment": "^24.9.0", "@jest/fake-timers": "^24.9.0", @@ -23538,50 +26093,11 @@ "jest-util": "^24.9.0" }, "dependencies": { - "@jest/console": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", - "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", - "requires": { - "@jest/source-map": "^24.9.0", - "chalk": "^2.0.1", - "slash": "^2.0.0" - } - }, - "@jest/fake-timers": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz", - "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", - "requires": { - "@jest/types": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-mock": "^24.9.0" - } - }, - "@jest/source-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", - "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.1.15", - "source-map": "^0.6.0" - } - }, - "@jest/test-result": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", - "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", - "requires": { - "@jest/console": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/istanbul-lib-coverage": "^2.0.0" - } - }, "@jest/types": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^1.1.1", @@ -23589,111 +26105,119 @@ } }, "@types/yargs": { - "version": "13.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.4.tgz", - "integrity": "sha512-Ke1WmBbIkVM8bpvsNEcGgQM70XcEh/nbpxQhW7FhrsbCsXSY9BmLB1+LHtD7r9zrsOcFlLiF+a/UeJsdfw3C5A==", + "version": "13.0.8", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz", + "integrity": "sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA==", + "dev": true, "requires": { "@types/yargs-parser": "*" } - }, - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" - }, - "jest-message-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", - "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", - "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/stack-utils": "^1.0.1", - "chalk": "^2.0.1", - "micromatch": "^3.1.10", - "slash": "^2.0.0", - "stack-utils": "^1.0.1" - } - }, - "jest-mock": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz", - "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", + } + } + }, + "jest-environment-puppeteer": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/jest-environment-puppeteer/-/jest-environment-puppeteer-4.4.0.tgz", + "integrity": "sha512-iV8S8+6qkdTM6OBR/M9gKywEk8GDSOe05hspCs5D8qKSwtmlUfdtHfB4cakdc68lC6YfK3AUsLirpfgodCHjzQ==", + "requires": { + "chalk": "^3.0.0", + "cwd": "^0.10.0", + "jest-dev-server": "^4.4.0", + "merge-deep": "^3.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", "requires": { - "@jest/types": "^24.9.0" + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" } }, - "jest-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz", - "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", "requires": { - "@jest/console": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/source-map": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "callsites": "^3.0.0", - "chalk": "^2.0.1", - "graceful-fs": "^4.1.15", - "is-ci": "^2.0.0", - "mkdirp": "^0.5.1", - "slash": "^2.0.0", - "source-map": "^0.6.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==" + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "requires": { + "has-flag": "^4.0.0" + } } } }, - "jest-environment-puppeteer": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/jest-environment-puppeteer/-/jest-environment-puppeteer-4.3.0.tgz", - "integrity": "sha512-ZighMsU39bnacn2ylyHb88CB+ldgCfXGD3lS78k4PEo8A8xyt6+2mxmSR62FH3Y7K+W2gPDu5+QM3/LZuq42fQ==", - "requires": { - "chalk": "^2.4.2", - "cwd": "^0.10.0", - "jest-dev-server": "^4.3.0", - "merge-deep": "^3.0.2" - } - }, "jest-get-type": { - "version": "24.3.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.3.0.tgz", - "integrity": "sha512-HYF6pry72YUlVcvUx3sEpMRwXEWGEPlJ0bSPVnB3b3n++j4phUEoSPcS6GC0pPJ9rpyPSe4cb5muFo6D39cXow==" + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", + "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==" }, "jest-haste-map": { - "version": "24.7.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.7.1.tgz", - "integrity": "sha512-g0tWkzjpHD2qa03mTKhlydbmmYiA2KdcJe762SbfFo/7NIMgBWAA0XqQlApPwkWOF7Cxoi/gUqL0i6DIoLpMBw==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.9.0.tgz", + "integrity": "sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ==", "requires": { - "@jest/types": "^24.7.0", + "@jest/types": "^24.9.0", "anymatch": "^2.0.0", "fb-watchman": "^2.0.0", "fsevents": "^1.2.7", "graceful-fs": "^4.1.15", "invariant": "^2.2.4", - "jest-serializer": "^24.4.0", - "jest-util": "^24.7.1", - "jest-worker": "^24.6.0", + "jest-serializer": "^24.9.0", + "jest-util": "^24.9.0", + "jest-worker": "^24.9.0", "micromatch": "^3.1.10", "sane": "^4.0.3", "walker": "^1.0.7" }, "dependencies": { + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@types/yargs": { + "version": "13.0.8", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz", + "integrity": "sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA==", + "requires": { + "@types/yargs-parser": "*" + } + }, "graceful-fs": { - "version": "4.1.15", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", - "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==" + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" } } }, @@ -23701,6 +26225,7 @@ "version": "24.9.0", "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-24.9.0.tgz", "integrity": "sha512-Cq7vkAgaYKp+PsX+2/JbTarrk0DmNhsEtqBXNwUHkdlbrTBLtMJINADf2mf5FkowNsq8evbPc07/qFO0AdKTzw==", + "dev": true, "requires": { "@babel/traverse": "^7.1.0", "@jest/environment": "^24.9.0", @@ -23720,50 +26245,11 @@ "throat": "^4.0.0" }, "dependencies": { - "@jest/console": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", - "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", - "requires": { - "@jest/source-map": "^24.9.0", - "chalk": "^2.0.1", - "slash": "^2.0.0" - } - }, - "@jest/fake-timers": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz", - "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", - "requires": { - "@jest/types": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-mock": "^24.9.0" - } - }, - "@jest/source-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", - "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.1.15", - "source-map": "^0.6.0" - } - }, - "@jest/test-result": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", - "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", - "requires": { - "@jest/console": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/istanbul-lib-coverage": "^2.0.0" - } - }, "@jest/types": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^1.1.1", @@ -23771,9 +26257,10 @@ } }, "@types/yargs": { - "version": "13.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.4.tgz", - "integrity": "sha512-Ke1WmBbIkVM8bpvsNEcGgQM70XcEh/nbpxQhW7FhrsbCsXSY9BmLB1+LHtD7r9zrsOcFlLiF+a/UeJsdfw3C5A==", + "version": "13.0.8", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz", + "integrity": "sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA==", + "dev": true, "requires": { "@types/yargs-parser": "*" } @@ -23781,51 +26268,25 @@ "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" - }, - "diff-sequences": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz", - "integrity": "sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==" - }, - "expect": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-24.9.0.tgz", - "integrity": "sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q==", - "requires": { - "@jest/types": "^24.9.0", - "ansi-styles": "^3.2.0", - "jest-get-type": "^24.9.0", - "jest-matcher-utils": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-regex-util": "^24.9.0" - } - }, - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true }, - "jest-diff": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.9.0.tgz", - "integrity": "sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==", + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, "requires": { - "chalk": "^2.0.1", - "diff-sequences": "^24.9.0", - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, - "jest-get-type": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", - "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==" - }, "jest-matcher-utils": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz", "integrity": "sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA==", + "dev": true, "requires": { "chalk": "^2.0.1", "jest-diff": "^24.9.0", @@ -23833,89 +26294,101 @@ "pretty-format": "^24.9.0" } }, - "jest-message-util": { + "pretty-format": { "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", - "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", + "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", + "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/test-result": "^24.9.0", "@jest/types": "^24.9.0", - "@types/stack-utils": "^1.0.1", - "chalk": "^2.0.1", - "micromatch": "^3.1.10", - "slash": "^2.0.0", - "stack-utils": "^1.0.1" + "ansi-regex": "^4.0.0", + "ansi-styles": "^3.2.0", + "react-is": "^16.8.4" } - }, - "jest-mock": { + } + } + }, + "jest-junit": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/jest-junit/-/jest-junit-10.0.0.tgz", + "integrity": "sha512-dbOVRyxHprdSpwSAR9/YshLwmnwf+RSl5hf0kCGlhAcEeZY9aRqo4oNmaT0tLC16Zy9D0zekDjWkjHGjXlglaQ==", + "dev": true, + "requires": { + "jest-validate": "^24.9.0", + "mkdirp": "^0.5.1", + "strip-ansi": "^5.2.0", + "uuid": "^3.3.3", + "xml": "^1.0.1" + }, + "dependencies": { + "@jest/types": { "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz", - "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, "requires": { - "@jest/types": "^24.9.0" + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" } }, - "jest-regex-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz", - "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==" - }, - "jest-resolve": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.9.0.tgz", - "integrity": "sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ==", + "@types/yargs": { + "version": "13.0.8", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz", + "integrity": "sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA==", + "dev": true, "requires": { - "@jest/types": "^24.9.0", - "browser-resolve": "^1.11.3", - "chalk": "^2.0.1", - "jest-pnp-resolver": "^1.2.1", - "realpath-native": "^1.1.0" + "@types/yargs-parser": "*" } }, - "jest-snapshot": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-24.9.0.tgz", - "integrity": "sha512-uI/rszGSs73xCM0l+up7O7a40o90cnrk429LOiK3aeTvfC0HHmldbd81/B7Ix81KSFe1lwkbl7GnBGG4UfuDew==", + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, "requires": { - "@babel/types": "^7.0.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "expect": "^24.9.0", - "jest-diff": "^24.9.0", - "jest-get-type": "^24.9.0", - "jest-matcher-utils": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-resolve": "^24.9.0", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "pretty-format": "^24.9.0", - "semver": "^6.2.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, - "jest-util": { + "jest-validate": { "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz", - "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.9.0.tgz", + "integrity": "sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ==", + "dev": true, "requires": { - "@jest/console": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/source-map": "^24.9.0", - "@jest/test-result": "^24.9.0", "@jest/types": "^24.9.0", - "callsites": "^3.0.0", + "camelcase": "^5.3.1", "chalk": "^2.0.1", - "graceful-fs": "^4.1.15", - "is-ci": "^2.0.0", - "mkdirp": "^0.5.1", - "slash": "^2.0.0", - "source-map": "^0.6.0" + "jest-get-type": "^24.9.0", + "leven": "^3.1.0", + "pretty-format": "^24.9.0" } }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + }, "pretty-format": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", + "dev": true, "requires": { "@jest/types": "^24.9.0", "ansi-regex": "^4.0.0", @@ -23923,39 +26396,28 @@ "react-is": "^16.8.4" } }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - }, - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==" + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true } } }, - "jest-junit": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/jest-junit/-/jest-junit-6.4.0.tgz", - "integrity": "sha512-GXEZA5WBeUich94BARoEUccJumhCgCerg7mXDFLxWwI2P7wL3Z7sGWk+53x343YdBLjiMR9aD/gYMVKO+0pE4Q==", - "dev": true, - "requires": { - "jest-validate": "^24.0.0", - "mkdirp": "^0.5.1", - "strip-ansi": "^4.0.0", - "xml": "^1.0.1" - } - }, "jest-leak-detector": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-24.9.0.tgz", "integrity": "sha512-tYkFIDsiKTGwb2FG1w8hX9V0aUb2ot8zY/2nFg087dUageonw1zrLMP4W6zsRO59dPkTSKie+D4rhMuP9nRmrA==", + "dev": true, "requires": { "jest-get-type": "^24.9.0", "pretty-format": "^24.9.0" @@ -23965,6 +26427,7 @@ "version": "24.9.0", "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^1.1.1", @@ -23972,9 +26435,10 @@ } }, "@types/yargs": { - "version": "13.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.4.tgz", - "integrity": "sha512-Ke1WmBbIkVM8bpvsNEcGgQM70XcEh/nbpxQhW7FhrsbCsXSY9BmLB1+LHtD7r9zrsOcFlLiF+a/UeJsdfw3C5A==", + "version": "13.0.8", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz", + "integrity": "sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA==", + "dev": true, "requires": { "@types/yargs-parser": "*" } @@ -23982,17 +26446,14 @@ "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" - }, - "jest-get-type": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", - "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==" + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true }, "pretty-format": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", + "dev": true, "requires": { "@jest/types": "^24.9.0", "ansi-regex": "^4.0.0", @@ -24003,24 +26464,112 @@ } }, "jest-matcher-utils": { - "version": "24.7.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.7.0.tgz", - "integrity": "sha512-158ieSgk3LNXeUhbVJYRXyTPSCqNgVXOp/GT7O94mYd3pk/8+odKTyR1JLtNOQSPzNi8NFYVONtvSWA/e1RDXg==", + "version": "25.3.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-25.3.0.tgz", + "integrity": "sha512-ZBUJ2fchNIZt+fyzkuCFBb8SKaU//Rln45augfUtbHaGyVxCO++ANARdBK9oPGXU3hEDgyy7UHnOP/qNOJXFUg==", "requires": { - "chalk": "^2.0.1", - "jest-diff": "^24.7.0", - "jest-get-type": "^24.3.0", - "pretty-format": "^24.7.0" + "chalk": "^3.0.0", + "jest-diff": "^25.3.0", + "jest-get-type": "^25.2.6", + "pretty-format": "^25.3.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + }, + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "diff-sequences": { + "version": "25.2.6", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-25.2.6.tgz", + "integrity": "sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "jest-diff": { + "version": "25.3.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-25.3.0.tgz", + "integrity": "sha512-vyvs6RPoVdiwARwY4kqFWd4PirPLm2dmmkNzKqo38uZOzJvLee87yzDjIZLmY1SjM3XR5DwsUH+cdQ12vgqi1w==", + "requires": { + "chalk": "^3.0.0", + "diff-sequences": "^25.2.6", + "jest-get-type": "^25.2.6", + "pretty-format": "^25.3.0" + } + }, + "jest-get-type": { + "version": "25.2.6", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.2.6.tgz", + "integrity": "sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig==" + }, + "pretty-format": { + "version": "25.3.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.3.0.tgz", + "integrity": "sha512-wToHwF8bkQknIcFkBqNfKu4+UZqnrLn/Vr+wwKQwwvPzkBfDDKp/qIabFqdgtoi5PEnM8LFByVsOrHoa3SpTVA==", + "requires": { + "@jest/types": "^25.3.0", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^16.12.0" + } + }, + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "requires": { + "has-flag": "^4.0.0" + } + } } }, "jest-message-util": { - "version": "24.7.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.7.1.tgz", - "integrity": "sha512-dk0gqVtyqezCHbcbk60CdIf+8UHgD+lmRHifeH3JRcnAqh4nEyPytSc9/L1+cQyxC+ceaeP696N4ATe7L+omcg==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", + "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", "requires": { "@babel/code-frame": "^7.0.0", - "@jest/test-result": "^24.7.1", - "@jest/types": "^24.7.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", "@types/stack-utils": "^1.0.1", "chalk": "^2.0.1", "micromatch": "^3.1.10", @@ -24028,6 +26577,34 @@ "stack-utils": "^1.0.1" }, "dependencies": { + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@types/yargs": { + "version": "13.0.8", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz", + "integrity": "sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, "slash": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", @@ -24036,11 +26613,31 @@ } }, "jest-mock": { - "version": "24.7.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.7.0.tgz", - "integrity": "sha512-6taW4B4WUcEiT2V9BbOmwyGuwuAFT2G8yghF7nyNW1/2gq5+6aTqSPcS9lS6ArvEkX55vbPAS/Jarx5LSm4Fng==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz", + "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", "requires": { - "@jest/types": "^24.7.0" + "@jest/types": "^24.9.0" + }, + "dependencies": { + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@types/yargs": { + "version": "13.0.8", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz", + "integrity": "sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA==", + "requires": { + "@types/yargs-parser": "*" + } + } } }, "jest-pnp-resolver": { @@ -24049,18 +26646,19 @@ "integrity": "sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ==" }, "jest-puppeteer": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/jest-puppeteer/-/jest-puppeteer-4.3.0.tgz", - "integrity": "sha512-WXhaWlbQl01xadZyNmdZntrtIr8uWUmgjPogDih7dOnr3G/xRr3A034SCqdjwV6fE0tqz7c5hwO8oBTyGZPRgA==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/jest-puppeteer/-/jest-puppeteer-4.4.0.tgz", + "integrity": "sha512-ZaiCTlPZ07B9HW0erAWNX6cyzBqbXMM7d2ugai4epBDKpKvRDpItlRQC6XjERoJELKZsPziFGS0OhhUvTvQAXA==", "requires": { - "expect-puppeteer": "^4.3.0", - "jest-environment-puppeteer": "^4.3.0" + "expect-puppeteer": "^4.4.0", + "jest-environment-puppeteer": "^4.4.0" } }, "jest-regex-util": { - "version": "24.3.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.3.0.tgz", - "integrity": "sha512-tXQR1NEOyGlfylyEjg1ImtScwMq8Oh3iJbGTjN7p0J23EuVX1MA8rwU69K4sLbCmwzgCUbVkm0FkSF9TdzOhtg==" + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz", + "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==", + "dev": true }, "jest-resolve": { "version": "24.9.0", @@ -24087,13 +26685,24 @@ } }, "@types/yargs": { - "version": "13.0.6", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.6.tgz", - "integrity": "sha512-IkltIncDQWv6fcAvnHtJ6KtkmY/vtR3bViOaCzpj/A3yNhlfZAgxNe6AEQD1cQrkYD+YsKVo08DSxvNKEsD7BA==", + "version": "13.0.8", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz", + "integrity": "sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA==", "dev": true, "requires": { "@types/yargs-parser": "*" } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } } } }, @@ -24101,194 +26710,32 @@ "version": "24.9.0", "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-24.9.0.tgz", "integrity": "sha512-Fm7b6AlWnYhT0BXy4hXpactHIqER7erNgIsIozDXWl5dVm+k8XdGVe1oTg1JyaFnOxarMEbax3wyRJqGP2Pq+g==", + "dev": true, "requires": { "@jest/types": "^24.9.0", "jest-regex-util": "^24.3.0", "jest-snapshot": "^24.9.0" }, "dependencies": { - "@jest/console": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", - "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", - "requires": { - "@jest/source-map": "^24.9.0", - "chalk": "^2.0.1", - "slash": "^2.0.0" - } - }, - "@jest/source-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", - "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.1.15", - "source-map": "^0.6.0" - } - }, - "@jest/test-result": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", - "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", - "requires": { - "@jest/console": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/istanbul-lib-coverage": "^2.0.0" - } - }, "@jest/types": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^13.0.0" - } - }, - "@types/yargs": { - "version": "13.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.4.tgz", - "integrity": "sha512-Ke1WmBbIkVM8bpvsNEcGgQM70XcEh/nbpxQhW7FhrsbCsXSY9BmLB1+LHtD7r9zrsOcFlLiF+a/UeJsdfw3C5A==", - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" - }, - "diff-sequences": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz", - "integrity": "sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==" - }, - "expect": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-24.9.0.tgz", - "integrity": "sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q==", - "requires": { - "@jest/types": "^24.9.0", - "ansi-styles": "^3.2.0", - "jest-get-type": "^24.9.0", - "jest-matcher-utils": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-regex-util": "^24.9.0" - }, - "dependencies": { - "jest-regex-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz", - "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==" - } - } - }, - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" - }, - "jest-diff": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.9.0.tgz", - "integrity": "sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==", - "requires": { - "chalk": "^2.0.1", - "diff-sequences": "^24.9.0", - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" - } - }, - "jest-get-type": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", - "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==" - }, - "jest-matcher-utils": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz", - "integrity": "sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA==", - "requires": { - "chalk": "^2.0.1", - "jest-diff": "^24.9.0", - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" - } - }, - "jest-message-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", - "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", - "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/stack-utils": "^1.0.1", - "chalk": "^2.0.1", - "micromatch": "^3.1.10", - "slash": "^2.0.0", - "stack-utils": "^1.0.1" - } - }, - "jest-resolve": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.9.0.tgz", - "integrity": "sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ==", - "requires": { - "@jest/types": "^24.9.0", - "browser-resolve": "^1.11.3", - "chalk": "^2.0.1", - "jest-pnp-resolver": "^1.2.1", - "realpath-native": "^1.1.0" - } - }, - "jest-snapshot": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-24.9.0.tgz", - "integrity": "sha512-uI/rszGSs73xCM0l+up7O7a40o90cnrk429LOiK3aeTvfC0HHmldbd81/B7Ix81KSFe1lwkbl7GnBGG4UfuDew==", - "requires": { - "@babel/types": "^7.0.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "expect": "^24.9.0", - "jest-diff": "^24.9.0", - "jest-get-type": "^24.9.0", - "jest-matcher-utils": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-resolve": "^24.9.0", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "pretty-format": "^24.9.0", - "semver": "^6.2.0" - } - }, - "pretty-format": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", - "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", - "requires": { - "@jest/types": "^24.9.0", - "ansi-regex": "^4.0.0", - "ansi-styles": "^3.2.0", - "react-is": "^16.8.4" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - }, - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==" + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "@types/yargs": { + "version": "13.0.8", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz", + "integrity": "sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } } } }, @@ -24296,6 +26743,7 @@ "version": "24.9.0", "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-24.9.0.tgz", "integrity": "sha512-KksJQyI3/0mhcfspnxxEOBueGrd5E4vV7ADQLT9ESaCzz02WnbdbKWIf5Mkaucoaj7obQckYPVX6JJhgUcoWWg==", + "dev": true, "requires": { "@jest/console": "^24.7.1", "@jest/environment": "^24.9.0", @@ -24318,52 +26766,11 @@ "throat": "^4.0.0" }, "dependencies": { - "@jest/fake-timers": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz", - "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", - "requires": { - "@jest/types": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-mock": "^24.9.0" - } - }, - "@jest/source-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", - "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.1.15", - "source-map": "^0.6.0" - } - }, - "@jest/test-result": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", - "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", - "requires": { - "@jest/console": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/istanbul-lib-coverage": "^2.0.0" - }, - "dependencies": { - "@jest/console": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", - "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", - "requires": { - "@jest/source-map": "^24.9.0", - "chalk": "^2.0.1", - "slash": "^2.0.0" - } - } - } - }, "@jest/types": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^1.1.1", @@ -24371,141 +26778,30 @@ } }, "@types/yargs": { - "version": "13.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.4.tgz", - "integrity": "sha512-Ke1WmBbIkVM8bpvsNEcGgQM70XcEh/nbpxQhW7FhrsbCsXSY9BmLB1+LHtD7r9zrsOcFlLiF+a/UeJsdfw3C5A==", + "version": "13.0.8", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz", + "integrity": "sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA==", + "dev": true, "requires": { "@types/yargs-parser": "*" } }, - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" - }, - "jest-haste-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.9.0.tgz", - "integrity": "sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ==", - "requires": { - "@jest/types": "^24.9.0", - "anymatch": "^2.0.0", - "fb-watchman": "^2.0.0", - "fsevents": "^1.2.7", - "graceful-fs": "^4.1.15", - "invariant": "^2.2.4", - "jest-serializer": "^24.9.0", - "jest-util": "^24.9.0", - "jest-worker": "^24.9.0", - "micromatch": "^3.1.10", - "sane": "^4.0.3", - "walker": "^1.0.7" - }, - "dependencies": { - "jest-worker": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", - "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", - "requires": { - "merge-stream": "^2.0.0", - "supports-color": "^6.1.0" - } - } - } - }, - "jest-message-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", - "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", - "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/stack-utils": "^1.0.1", - "chalk": "^2.0.1", - "micromatch": "^3.1.10", - "slash": "^2.0.0", - "stack-utils": "^1.0.1" - } - }, - "jest-mock": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz", - "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", - "requires": { - "@jest/types": "^24.9.0" - } - }, - "jest-resolve": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.9.0.tgz", - "integrity": "sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ==", - "requires": { - "@jest/types": "^24.9.0", - "browser-resolve": "^1.11.3", - "chalk": "^2.0.1", - "jest-pnp-resolver": "^1.2.1", - "realpath-native": "^1.1.0" - } - }, - "jest-serializer": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.9.0.tgz", - "integrity": "sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ==" - }, - "jest-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz", - "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, "requires": { - "@jest/console": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/source-map": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "callsites": "^3.0.0", - "chalk": "^2.0.1", - "graceful-fs": "^4.1.15", - "is-ci": "^2.0.0", - "mkdirp": "^0.5.1", - "slash": "^2.0.0", - "source-map": "^0.6.0" - }, - "dependencies": { - "@jest/console": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", - "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", - "requires": { - "@jest/source-map": "^24.9.0", - "chalk": "^2.0.1", - "slash": "^2.0.0" - } - } + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" - }, - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } + "graceful-fs": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", + "dev": true } } }, @@ -24513,6 +26809,7 @@ "version": "24.9.0", "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-24.9.0.tgz", "integrity": "sha512-8oNqgnmF3v2J6PVRM2Jfuj8oX3syKmaynlDMMKQ4iyzbQzIG6th5ub/lM2bCMTmoTKM3ykcUYI2Pw9xwNtjMnw==", + "dev": true, "requires": { "@jest/console": "^24.7.1", "@jest/environment": "^24.9.0", @@ -24539,52 +26836,11 @@ "yargs": "^13.3.0" }, "dependencies": { - "@jest/fake-timers": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz", - "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", - "requires": { - "@jest/types": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-mock": "^24.9.0" - } - }, - "@jest/test-result": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", - "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", - "requires": { - "@jest/console": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/istanbul-lib-coverage": "^2.0.0" - }, - "dependencies": { - "@jest/console": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", - "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", - "requires": { - "@jest/source-map": "^24.9.0", - "chalk": "^2.0.1", - "slash": "^2.0.0" - } - }, - "@jest/source-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", - "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.1.15", - "source-map": "^0.6.0" - } - } - } - }, "@jest/types": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^1.1.1", @@ -24592,9 +26848,10 @@ } }, "@types/yargs": { - "version": "13.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.4.tgz", - "integrity": "sha512-Ke1WmBbIkVM8bpvsNEcGgQM70XcEh/nbpxQhW7FhrsbCsXSY9BmLB1+LHtD7r9zrsOcFlLiF+a/UeJsdfw3C5A==", + "version": "13.0.8", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz", + "integrity": "sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA==", + "dev": true, "requires": { "@types/yargs-parser": "*" } @@ -24602,52 +26859,42 @@ "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true }, "camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } }, "cliui": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, "requires": { "string-width": "^3.1.0", "strip-ansi": "^5.2.0", "wrap-ansi": "^5.1.0" } }, - "diff-sequences": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz", - "integrity": "sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==" - }, - "expect": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-24.9.0.tgz", - "integrity": "sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q==", - "requires": { - "@jest/types": "^24.9.0", - "ansi-styles": "^3.2.0", - "jest-get-type": "^24.9.0", - "jest-matcher-utils": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-regex-util": "^24.9.0" - }, - "dependencies": { - "jest-regex-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz", - "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==" - } - } - }, "find-up": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, "requires": { "locate-path": "^3.0.0" } @@ -24655,12 +26902,14 @@ "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true }, "glob": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -24673,200 +26922,24 @@ "graceful-fs": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" - }, - "jest-diff": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.9.0.tgz", - "integrity": "sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==", - "requires": { - "chalk": "^2.0.1", - "diff-sequences": "^24.9.0", - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" - } - }, - "jest-get-type": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", - "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==" - }, - "jest-haste-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.9.0.tgz", - "integrity": "sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ==", - "requires": { - "@jest/types": "^24.9.0", - "anymatch": "^2.0.0", - "fb-watchman": "^2.0.0", - "fsevents": "^1.2.7", - "graceful-fs": "^4.1.15", - "invariant": "^2.2.4", - "jest-serializer": "^24.9.0", - "jest-util": "^24.9.0", - "jest-worker": "^24.9.0", - "micromatch": "^3.1.10", - "sane": "^4.0.3", - "walker": "^1.0.7" - } - }, - "jest-matcher-utils": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz", - "integrity": "sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA==", - "requires": { - "chalk": "^2.0.1", - "jest-diff": "^24.9.0", - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" - } - }, - "jest-message-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", - "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", - "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/stack-utils": "^1.0.1", - "chalk": "^2.0.1", - "micromatch": "^3.1.10", - "slash": "^2.0.0", - "stack-utils": "^1.0.1" - } - }, - "jest-mock": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz", - "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", - "requires": { - "@jest/types": "^24.9.0" - } - }, - "jest-resolve": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.9.0.tgz", - "integrity": "sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ==", - "requires": { - "@jest/types": "^24.9.0", - "browser-resolve": "^1.11.3", - "chalk": "^2.0.1", - "jest-pnp-resolver": "^1.2.1", - "realpath-native": "^1.1.0" - } - }, - "jest-serializer": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.9.0.tgz", - "integrity": "sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ==" - }, - "jest-snapshot": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-24.9.0.tgz", - "integrity": "sha512-uI/rszGSs73xCM0l+up7O7a40o90cnrk429LOiK3aeTvfC0HHmldbd81/B7Ix81KSFe1lwkbl7GnBGG4UfuDew==", - "requires": { - "@babel/types": "^7.0.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "expect": "^24.9.0", - "jest-diff": "^24.9.0", - "jest-get-type": "^24.9.0", - "jest-matcher-utils": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-resolve": "^24.9.0", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "pretty-format": "^24.9.0", - "semver": "^6.2.0" - } - }, - "jest-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz", - "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", - "requires": { - "@jest/console": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/source-map": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "callsites": "^3.0.0", - "chalk": "^2.0.1", - "graceful-fs": "^4.1.15", - "is-ci": "^2.0.0", - "mkdirp": "^0.5.1", - "slash": "^2.0.0", - "source-map": "^0.6.0" - }, - "dependencies": { - "@jest/console": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", - "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", - "requires": { - "@jest/source-map": "^24.9.0", - "chalk": "^2.0.1", - "slash": "^2.0.0" - } - }, - "@jest/source-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", - "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.1.15", - "source-map": "^0.6.0" - } - } - } - }, - "jest-validate": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.9.0.tgz", - "integrity": "sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ==", - "requires": { - "@jest/types": "^24.9.0", - "camelcase": "^5.3.1", - "chalk": "^2.0.1", - "jest-get-type": "^24.9.0", - "leven": "^3.1.0", - "pretty-format": "^24.9.0" - } - }, - "jest-worker": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", - "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", - "requires": { - "merge-stream": "^2.0.0", - "supports-color": "^6.1.0" - } - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", + "dev": true }, "locate-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, "requires": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" - }, "p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, "requires": { "p-try": "^2.0.0" } @@ -24875,6 +26948,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, "requires": { "p-limit": "^2.0.0" } @@ -24882,43 +26956,26 @@ "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" - }, - "pretty-format": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", - "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", - "requires": { - "@jest/types": "^24.9.0", - "ansi-regex": "^4.0.0", - "ansi-styles": "^3.2.0", - "react-is": "^16.8.4" - } + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true }, "require-main-filename": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true }, "slash": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, "requires": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", @@ -24929,6 +26986,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, "requires": { "ansi-regex": "^4.1.0" } @@ -24936,20 +26994,14 @@ "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true }, "wrap-ansi": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, "requires": { "ansi-styles": "^3.2.0", "string-width": "^3.0.0", @@ -24959,12 +27011,14 @@ "y18n": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true }, "yargs": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", - "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, "requires": { "cliui": "^5.0.0", "find-up": "^3.0.0", @@ -24975,15 +27029,25 @@ "string-width": "^3.0.0", "which-module": "^2.0.0", "y18n": "^4.0.0", - "yargs-parser": "^13.1.1" + "yargs-parser": "^13.1.2" + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" } } } }, "jest-serializer": { - "version": "24.4.0", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.4.0.tgz", - "integrity": "sha512-k//0DtglVstc1fv+GY/VHDIjrtNjdYvYjMlbLUed4kxrE92sIUewOi5Hj3vrpB8CXfkJntRPDRjCrCvUhBdL8Q==" + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.9.0.tgz", + "integrity": "sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ==" }, "jest-serializer-enzyme": { "version": "1.0.0", @@ -25032,39 +27096,153 @@ "semver": "^6.2.0" }, "dependencies": { - "@jest/console": { + "@jest/types": { "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", - "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", "dev": true, "requires": { - "@jest/source-map": "^24.9.0", - "chalk": "^2.0.1", - "slash": "^2.0.0" + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" } }, - "@jest/source-map": { + "@types/yargs": { + "version": "13.0.8", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz", + "integrity": "sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "jest-matcher-utils": { "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", - "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz", + "integrity": "sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA==", "dev": true, "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.1.15", - "source-map": "^0.6.0" + "chalk": "^2.0.1", + "jest-diff": "^24.9.0", + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" } }, - "@jest/test-result": { + "pretty-format": { "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", - "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", + "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", "dev": true, "requires": { - "@jest/console": "^24.9.0", "@jest/types": "^24.9.0", - "@types/istanbul-lib-coverage": "^2.0.0" + "ansi-regex": "^4.0.0", + "ansi-styles": "^3.2.0", + "react-is": "^16.8.4" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "jest-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz", + "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", + "requires": { + "@jest/console": "^24.9.0", + "@jest/fake-timers": "^24.9.0", + "@jest/source-map": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "callsites": "^3.0.0", + "chalk": "^2.0.1", + "graceful-fs": "^4.1.15", + "is-ci": "^2.0.0", + "mkdirp": "^0.5.1", + "slash": "^2.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@types/yargs": { + "version": "13.0.8", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz", + "integrity": "sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, + "graceful-fs": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "jest-validate": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.9.0.tgz", + "integrity": "sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "camelcase": "^5.3.1", + "chalk": "^2.0.1", + "jest-get-type": "^24.9.0", + "leven": "^3.1.0", + "pretty-format": "^24.9.0" + }, + "dependencies": { "@jest/types": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", @@ -25077,9 +27255,9 @@ } }, "@types/yargs": { - "version": "13.0.6", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.6.tgz", - "integrity": "sha512-IkltIncDQWv6fcAvnHtJ6KtkmY/vtR3bViOaCzpj/A3yNhlfZAgxNe6AEQD1cQrkYD+YsKVo08DSxvNKEsD7BA==", + "version": "13.0.8", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz", + "integrity": "sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -25091,64 +27269,29 @@ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, - "diff-sequences": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz", - "integrity": "sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==", - "dev": true - }, - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, - "jest-diff": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.9.0.tgz", - "integrity": "sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==", + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { - "chalk": "^2.0.1", - "diff-sequences": "^24.9.0", - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, - "jest-get-type": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", - "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==", + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", "dev": true }, - "jest-matcher-utils": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz", - "integrity": "sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA==", - "dev": true, - "requires": { - "chalk": "^2.0.1", - "jest-diff": "^24.9.0", - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" - } - }, - "jest-message-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", - "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/stack-utils": "^1.0.1", - "chalk": "^2.0.1", - "micromatch": "^3.1.10", - "slash": "^2.0.0", - "stack-utils": "^1.0.1" - } - }, "pretty-format": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", @@ -25160,89 +27303,6 @@ "ansi-styles": "^3.2.0", "react-is": "^16.8.4" } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - }, - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "jest-specific-snapshot": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/jest-specific-snapshot/-/jest-specific-snapshot-2.0.0.tgz", - "integrity": "sha512-aXaNqBg/svwEpY5iQEzEHc5I85cUBKgfeVka9KmpznxLnatpjiqjr7QLb/BYNYlsrZjZzgRHTjQJ+Svx+dbdvg==", - "dev": true, - "requires": { - "jest-snapshot": "^24.1.0" - } - }, - "jest-util": { - "version": "24.7.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.7.1.tgz", - "integrity": "sha512-/KilOue2n2rZ5AnEBYoxOXkeTu6vi7cjgQ8MXEkih0oeAXT6JkS3fr7/j8+engCjciOU1Nq5loMSKe0A1oeX0A==", - "requires": { - "@jest/console": "^24.7.1", - "@jest/fake-timers": "^24.7.1", - "@jest/source-map": "^24.3.0", - "@jest/test-result": "^24.7.1", - "@jest/types": "^24.7.0", - "callsites": "^3.0.0", - "chalk": "^2.0.1", - "graceful-fs": "^4.1.15", - "is-ci": "^2.0.0", - "mkdirp": "^0.5.1", - "slash": "^2.0.0", - "source-map": "^0.6.0" - }, - "dependencies": { - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" - }, - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "jest-validate": { - "version": "24.7.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.7.0.tgz", - "integrity": "sha512-cgai/gts9B2chz1rqVdmLhzYxQbgQurh1PEQSvSgPZ8KGa1AqXsqC45W5wKEwzxKrWqypuQrQxnF4+G9VejJJA==", - "requires": { - "@jest/types": "^24.7.0", - "camelcase": "^5.0.0", - "chalk": "^2.0.1", - "jest-get-type": "^24.3.0", - "leven": "^2.1.0", - "pretty-format": "^24.7.0" - }, - "dependencies": { - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" } } }, @@ -25250,6 +27310,7 @@ "version": "24.9.0", "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-24.9.0.tgz", "integrity": "sha512-+/fLOfKPXXYJDYlks62/4R4GoT+GU1tYZed99JSCOsmzkkF7727RqKrjNAxtfO4YpGv11wybgRvCjR73lK2GZw==", + "dev": true, "requires": { "@jest/test-result": "^24.9.0", "@jest/types": "^24.9.0", @@ -25260,50 +27321,11 @@ "string-length": "^2.0.0" }, "dependencies": { - "@jest/console": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", - "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", - "requires": { - "@jest/source-map": "^24.9.0", - "chalk": "^2.0.1", - "slash": "^2.0.0" - } - }, - "@jest/fake-timers": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz", - "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", - "requires": { - "@jest/types": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-mock": "^24.9.0" - } - }, - "@jest/source-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", - "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.1.15", - "source-map": "^0.6.0" - } - }, - "@jest/test-result": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", - "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", - "requires": { - "@jest/console": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/istanbul-lib-coverage": "^2.0.0" - } - }, "@jest/types": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^1.1.1", @@ -25311,81 +27333,51 @@ } }, "@types/yargs": { - "version": "13.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.4.tgz", - "integrity": "sha512-Ke1WmBbIkVM8bpvsNEcGgQM70XcEh/nbpxQhW7FhrsbCsXSY9BmLB1+LHtD7r9zrsOcFlLiF+a/UeJsdfw3C5A==", + "version": "13.0.8", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz", + "integrity": "sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA==", + "dev": true, "requires": { "@types/yargs-parser": "*" } }, - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" - }, - "jest-message-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", - "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", - "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/stack-utils": "^1.0.1", - "chalk": "^2.0.1", - "micromatch": "^3.1.10", - "slash": "^2.0.0", - "stack-utils": "^1.0.1" - } - }, - "jest-mock": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz", - "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, "requires": { - "@jest/types": "^24.9.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, - "jest-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz", - "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", + "string-length": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", + "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", + "dev": true, "requires": { - "@jest/console": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/source-map": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "callsites": "^3.0.0", - "chalk": "^2.0.1", - "graceful-fs": "^4.1.15", - "is-ci": "^2.0.0", - "mkdirp": "^0.5.1", - "slash": "^2.0.0", - "source-map": "^0.6.0" + "astral-regex": "^1.0.0", + "strip-ansi": "^4.0.0" } - }, - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" } } }, "jest-worker": { - "version": "24.6.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.6.0.tgz", - "integrity": "sha512-jDwgW5W9qGNvpI1tNnvajh0a5IE/PuGLFmHk6aR/BZFz8tSgGw17GsDPXAJ6p91IvYDjOw8GpFbvvZGAK+DPQQ==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", + "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", "requires": { - "merge-stream": "^1.0.1", + "merge-stream": "^2.0.0", "supports-color": "^6.1.0" }, "dependencies": { + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, "supports-color": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", @@ -25516,73 +27508,191 @@ } }, "jsdoctypeparser": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/jsdoctypeparser/-/jsdoctypeparser-5.0.1.tgz", - "integrity": "sha512-dYwcK6TKzvq+ZKtbp4sbQSW9JMo6s+4YFfUs5D/K7bZsn3s1NhEhZ+jmIPzby0HbkbECBe+hNPEa6a+E21o94w==" + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsdoctypeparser/-/jsdoctypeparser-6.1.0.tgz", + "integrity": "sha512-UCQBZ3xCUBv/PLfwKAJhp6jmGOSLFNKzrotXGNgbKhWvz27wPsCsVeP7gIcHPElQw2agBmynAitXqhxR58XAmA==" }, "jsdom": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", - "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", + "version": "15.2.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-15.2.1.tgz", + "integrity": "sha512-fAl1W0/7T2G5vURSyxBzrJ1LSdQn6Tr5UX/xD4PXDx/PDgwygedfW6El/KIj3xJ7FU61TTYnc/l/B7P49Eqt6g==", "requires": { "abab": "^2.0.0", - "acorn": "^5.5.3", - "acorn-globals": "^4.1.0", + "acorn": "^7.1.0", + "acorn-globals": "^4.3.2", "array-equal": "^1.0.0", - "cssom": ">= 0.3.2 < 0.4.0", - "cssstyle": "^1.0.0", - "data-urls": "^1.0.0", + "cssom": "^0.4.1", + "cssstyle": "^2.0.0", + "data-urls": "^1.1.0", "domexception": "^1.0.1", - "escodegen": "^1.9.1", + "escodegen": "^1.11.1", "html-encoding-sniffer": "^1.0.2", - "left-pad": "^1.3.0", - "nwsapi": "^2.0.7", - "parse5": "4.0.0", + "nwsapi": "^2.2.0", + "parse5": "5.1.0", "pn": "^1.1.0", - "request": "^2.87.0", - "request-promise-native": "^1.0.5", - "sax": "^1.2.4", + "request": "^2.88.0", + "request-promise-native": "^1.0.7", + "saxes": "^3.1.9", "symbol-tree": "^3.2.2", - "tough-cookie": "^2.3.4", + "tough-cookie": "^3.0.1", "w3c-hr-time": "^1.0.1", + "w3c-xmlserializer": "^1.1.2", "webidl-conversions": "^4.0.2", - "whatwg-encoding": "^1.0.3", - "whatwg-mimetype": "^2.1.0", - "whatwg-url": "^6.4.1", - "ws": "^5.2.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^7.0.0", + "ws": "^7.0.0", "xml-name-validator": "^3.0.0" }, "dependencies": { "abab": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.0.tgz", - "integrity": "sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w==" + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.3.tgz", + "integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg==" }, - "cssstyle": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.1.1.tgz", - "integrity": "sha512-364AI1l/M5TYcFH83JnOH/pSqgaNnKmYgKrm0didZMGKWjQB60dymwWy1rKUgL3J1ffdq9xVi2yGLHdSjjSNog==", + "acorn": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz", + "integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==" + }, + "acorn-globals": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz", + "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==", "requires": { - "cssom": "0.3.x" + "acorn": "^6.0.1", + "acorn-walk": "^6.0.1" + }, + "dependencies": { + "acorn": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", + "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==" + } + } + }, + "acorn-walk": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", + "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==" + }, + "cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==" + }, + "data-urls": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", + "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", + "requires": { + "abab": "^2.0.0", + "whatwg-mimetype": "^2.2.0", + "whatwg-url": "^7.0.0" + } + }, + "escodegen": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.1.tgz", + "integrity": "sha512-Bmt7NcRySdIfNPfU2ZoXDrrXsG9ZjvDxcAlMfDUgRBjLOWTuIACXPBFJH7Z+cLb40JeQco5toikyc9t9P8E9SQ==", + "requires": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" } }, - "nwsapi": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.0.9.tgz", - "integrity": "sha512-nlWFSCTYQcHk/6A9FFnfhKc14c3aFhfdNBXgo8Qgi9QTBu/qg3Ww+Uiz9wMzXd1T8GFxPc2QIHB6Qtf2XFryFQ==" + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } }, "parse5": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", - "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==" + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz", + "integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==" }, - "ws": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", - "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", + "request-promise-core": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.3.tgz", + "integrity": "sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==", "requires": { - "async-limiter": "~1.0.0" + "lodash": "^4.17.15" + } + }, + "request-promise-native": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.8.tgz", + "integrity": "sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ==", + "requires": { + "request-promise-core": "1.1.3", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + }, + "dependencies": { + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + } } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true + }, + "tough-cookie": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", + "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==", + "requires": { + "ip-regex": "^2.1.0", + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "requires": { + "iconv-lite": "0.4.24" + } + }, + "whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==" + }, + "whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "ws": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.3.tgz", + "integrity": "sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ==" } } }, @@ -25599,6 +27709,11 @@ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.1.tgz", "integrity": "sha1-5CGiqOINawgZ3yiQj3glJrlt0f4=" }, + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" + }, "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", @@ -25713,10 +27828,13 @@ "set-immediate-shim": "~1.0.1" } }, - "keymirror": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/keymirror/-/keymirror-0.1.1.tgz", - "integrity": "sha1-kYiJ6hP40KQufFVyUO7nE63JXDU=" + "keyv": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.0.0.tgz", + "integrity": "sha512-U7ioE8AimvRVLfw4LffyOIRhL2xVgmE8T22L6i0BucSnBUyv4w+I7VN/zVZwRKHOI6ZRUcdMdWHQ8KSUvGpEog==", + "requires": { + "json-buffer": "3.0.1" + } }, "kind-of": { "version": "6.0.2", @@ -25794,7 +27912,8 @@ "left-pad": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", - "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==" + "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==", + "dev": true }, "lerna": { "version": "3.18.2", @@ -25826,21 +27945,6 @@ "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=" }, - "levenary": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/levenary/-/levenary-1.1.0.tgz", - "integrity": "sha512-VHcwhO0UTpUW7rLPN2/OiWJdgA1e9BqEDALhrgCe/F+uUJnep6CoUsTzMeP8Rh0NGr9uKquXxqe7lwLZo509nQ==", - "requires": { - "leven": "^3.1.0" - }, - "dependencies": { - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" - } - } - }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", @@ -25910,6 +28014,17 @@ "fill-range": "^7.0.1" } }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, "commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -26251,6 +28366,19 @@ "cli-cursor": "^2.1.0", "date-fns": "^1.27.2", "figures": "^2.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } } }, "livereload-js": { @@ -26440,11 +28568,6 @@ "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=" }, - "lodash.unescape": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz", - "integrity": "sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw=" - }, "lodash.union": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", @@ -26462,6 +28585,18 @@ "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", "requires": { "chalk": "^2.0.1" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } } }, "log-update": { @@ -26661,6 +28796,14 @@ } } }, + "lolex": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-5.1.2.tgz", + "integrity": "sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A==", + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, "longest": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", @@ -26695,6 +28838,11 @@ "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", "dev": true }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" + }, "lowlight": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.11.0.tgz", @@ -26725,7 +28873,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.0.0.tgz", "integrity": "sha512-grNJDhb8b1Jm1qeqW5R/O63wUo4UXo2v2HMic6YT9i/HBlF93S8jkMgH7yugvY9ABDShH4VZMn8I+U8+fCNegw==", - "dev": true, "requires": { "semver": "^6.0.0" }, @@ -26733,8 +28880,7 @@ "semver": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.0.0.tgz", - "integrity": "sha512-0UewU+9rFapKFnlbirLi3byoOuhrSsli/z/ihNnvM24vgF+8sNBiI1LZPBSH9wJKUwaUbw+s3hToDLCXkrghrQ==", - "dev": true + "integrity": "sha512-0UewU+9rFapKFnlbirLi3byoOuhrSsli/z/ihNnvM24vgF+8sNBiI1LZPBSH9wJKUwaUbw+s3hToDLCXkrghrQ==" } } }, @@ -27144,9 +29290,9 @@ } }, "memize": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/memize/-/memize-1.0.5.tgz", - "integrity": "sha512-Dm8Jhb5kiC4+ynYsVR4QDXKt+o2dfqGuY4hE2x+XlXZkdndlT80bJxfcMv5QGp/FCy6MhG7f5ElpmKPFKOSEpg==" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/memize/-/memize-1.1.0.tgz", + "integrity": "sha512-K4FcPETOMTwe7KL2LK0orMhpOmWD2wRGwWWpbZy0fyArwsyIKR8YJVz8+efBAh3BO4zPqlSICu4vsLTRRqtFAg==" }, "memoize-one": { "version": "5.1.1", @@ -27439,6 +29585,17 @@ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, "cliui": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", @@ -27518,6 +29675,20 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, "jsonfile": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", @@ -27748,6 +29919,15 @@ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "dev": true }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", @@ -27908,6 +30088,14 @@ "once": "^1.3.0", "path-is-absolute": "^1.0.0" } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } } } }, @@ -27924,10 +30112,43 @@ "pretty-format": "^24.7.0" }, "dependencies": { + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@types/yargs": { + "version": "13.0.8", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz", + "integrity": "sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA==", + "requires": { + "@types/yargs-parser": "*" + } + }, "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } }, "cliui": { "version": "3.2.0", @@ -27989,6 +30210,19 @@ "klaw": "^1.0.0" } }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, "is-fullwidth-code-point": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", @@ -27997,6 +30231,32 @@ "number-is-nan": "^1.0.0" } }, + "jest-validate": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.9.0.tgz", + "integrity": "sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ==", + "requires": { + "@jest/types": "^24.9.0", + "camelcase": "^5.3.1", + "chalk": "^2.0.1", + "jest-get-type": "^24.9.0", + "leven": "^3.1.0", + "pretty-format": "^24.9.0" + }, + "dependencies": { + "pretty-format": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", + "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", + "requires": { + "@jest/types": "^24.9.0", + "ansi-regex": "^4.0.0", + "ansi-styles": "^3.2.0", + "react-is": "^16.8.4" + } + } + } + }, "jsonfile": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", @@ -28005,6 +30265,11 @@ "graceful-fs": "^4.1.6" } }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" + }, "load-json-file": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", @@ -28163,11 +30428,6 @@ "mime-db": "~1.23.0" } }, - "node-fetch": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", - "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" - }, "path-type": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", @@ -28176,11 +30436,6 @@ "pify": "^2.0.0" } }, - "react-refresh": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.4.2.tgz", - "integrity": "sha512-kv5QlFFSZWo7OlJFNYbxRtY66JImuP2LcrFgyJfQaf85gSP+byzG21UbDQEYjU7f//ny8rwiEkO6py2Y+fEgAQ==" - }, "read-pkg": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", @@ -28200,6 +30455,14 @@ "read-pkg": "^2.0.0" } }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + }, "rxjs": { "version": "5.5.12", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.12.tgz", @@ -28214,6 +30477,13 @@ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + } } }, "strip-bom": { @@ -28263,6 +30533,13 @@ "which-module": "^2.0.0", "y18n": "^3.2.1", "yargs-parser": "^7.0.0" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=" + } } }, "yargs-parser": { @@ -28271,6 +30548,13 @@ "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=", "requires": { "camelcase": "^4.1.0" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=" + } } } } @@ -28736,6 +31020,11 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" }, + "mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==" + }, "min-document": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", @@ -28748,8 +31037,7 @@ "min-indent": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.0.tgz", - "integrity": "sha1-z8RcN+nsDY8KDsPdTvf3w6vjklY=", - "dev": true + "integrity": "sha1-z8RcN+nsDY8KDsPdTvf3w6vjklY=" }, "mini-css-extract-plugin": { "version": "0.8.2", @@ -28988,6 +31276,11 @@ } } }, + "mkdirp-classic": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.2.tgz", + "integrity": "sha512-ejdnDQcR75gwknmMw/tx02AuRs8jCtqFoFqDZMjiNxsu85sRIJVXDKHuLYvUUPRBUtV2FpSZa9bL1BUa3BdR2g==" + }, "mkdirp-promise": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz", @@ -29064,6 +31357,29 @@ "mkdirp": "^0.5.1", "rimraf": "^2.5.4", "run-queue": "^1.0.3" + }, + "dependencies": { + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + } } }, "ms": { @@ -29202,6 +31518,35 @@ "lower-case": "^1.1.1" } }, + "nock": { + "version": "12.0.3", + "resolved": "https://registry.npmjs.org/nock/-/nock-12.0.3.tgz", + "integrity": "sha512-QNb/j8kbFnKCiyqi9C5DD0jH/FubFGj5rt9NQFONXwQm3IPB0CULECg/eS3AU1KgZb/6SwUa4/DTRKhVxkGABw==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "json-stringify-safe": "^5.0.1", + "lodash": "^4.17.13", + "propagate": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, "node-dir": { "version": "0.1.17", "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", @@ -29247,6 +31592,31 @@ "which": "1" }, "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + }, + "dependencies": { + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, "semver": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", @@ -29298,11 +31668,12 @@ } }, "node-libs-react-native": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/node-libs-react-native/-/node-libs-react-native-1.0.3.tgz", - "integrity": "sha512-2X/M/DMB4hij2L0tsnJOiDhYR2N0YtetIhb/eN5+5vksLxjXwaFgLbSXWT3XExnGJpISDn8dYuYz6yvdndjjkg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/node-libs-react-native/-/node-libs-react-native-1.2.0.tgz", + "integrity": "sha512-D+g8Mj9OfsOYYFWZoSz4bmr/8g/QWOwUgDmi3Ux0EPU9Q41OvGsdzAzr0IGJmtuSAfyOTfnKx1XRQR9id8/EEw==", "requires": { "assert": "^1.4.1", + "base-64": "^0.1.0", "browserify-zlib": "^0.2.0", "buffer": "^5.0.6", "console-browserify": "^1.1.0", @@ -29327,9 +31698,9 @@ }, "dependencies": { "buffer": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.5.0.tgz", - "integrity": "sha512-9FTEDjLjwoAkEwyMGDjYJQN2gfRgOKBKRfiglhvibGbpeeU/pQn1bJxQqm32OD/AIeEuHxU9roxXxg34Byp/Ww==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", "requires": { "base64-js": "^1.0.2", "ieee754": "^1.1.4" @@ -29402,6 +31773,20 @@ "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==", "dev": true }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, "minipass": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", @@ -29422,6 +31807,15 @@ "osenv": "^0.1.4" } }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -29686,6 +32080,14 @@ "tough-cookie": "~2.4.3", "tunnel-agent": "^0.6.0", "uuid": "^3.3.2" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + } } }, "strip-ansi": { @@ -29803,6 +32205,33 @@ "semver": "~5.3.0", "tar": "^4.4.8", "which": "1" + }, + "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + }, + "dependencies": { + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + } } }, "semver": { @@ -29962,6 +32391,33 @@ "semver": "~5.3.0", "tar": "^4.4.12", "which": "1" + }, + "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + }, + "dependencies": { + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + } } }, "resolve-from": { @@ -30020,23 +32476,25 @@ } }, "npm-package-json-lint": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/npm-package-json-lint/-/npm-package-json-lint-4.0.3.tgz", - "integrity": "sha512-cuvTR2l5dOjjlRR3a1CCp+mh2A2HyQRxydwdcYi0Z77NRlADpf7wF3Jf8XFLGZM7J6afXNRBofBjQ1UWFyOtKA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/npm-package-json-lint/-/npm-package-json-lint-5.0.0.tgz", + "integrity": "sha512-a7meq98EnSqniPWNhTj0TMJbTFKr8SPEkQep3iPCQVJWfhQ8fKI5+bUSgNyEbYfzfIrIjMTb0r/tCkX7FX+bYQ==", "requires": { - "ajv": "^6.10.2", + "ajv": "^6.12.0", "ajv-errors": "^1.0.1", - "chalk": "^2.4.2", - "cosmiconfig": "^5.2.1", + "chalk": "^4.0.0", + "cosmiconfig": "^6.0.0", "debug": "^4.1.1", - "globby": "^10.0.1", + "globby": "^11.0.0", "ignore": "^5.1.4", - "is-plain-obj": "^2.0.0", + "is-plain-obj": "^2.1.0", + "jsonc-parser": "^2.2.1", "log-symbols": "^3.0.0", - "meow": "^5.0.0", - "plur": "^3.1.1", - "semver": "^6.3.0", - "strip-json-comments": "^3.0.1" + "meow": "^6.1.0", + "plur": "^4.0.0", + "semver": "^7.2.2", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.0" }, "dependencies": { "@nodelib/fs.stat": { @@ -30044,6 +32502,17 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==" }, + "ajv": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz", + "integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, "array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -30057,15 +32526,31 @@ "fill-range": "^7.0.1" } }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "requires": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + } + }, "cosmiconfig": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", - "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", "requires": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.0.0" + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" } }, "debug": { @@ -30076,13 +32561,10 @@ "ms": "^2.1.1" } }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "requires": { - "path-type": "^4.0.0" - } + "fast-deep-equal": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", + "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==" }, "fast-glob": { "version": "3.1.1", @@ -30094,13 +32576,6 @@ "glob-parent": "^5.1.0", "merge2": "^1.3.0", "micromatch": "^4.0.2" - }, - "dependencies": { - "merge2": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.3.0.tgz", - "integrity": "sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==" - } } }, "fill-range": { @@ -30111,17 +32586,13 @@ "to-regex-range": "^5.0.1" } }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" } }, "glob-parent": { @@ -30133,17 +32604,15 @@ } }, "globby": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz", - "integrity": "sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.0.tgz", + "integrity": "sha512-iuehFnR3xu5wBBtm4xi0dMe92Ob87ufyu/dHwpDYfbcpYpIbrO5OnS8M1vWvrBhSGEJ3/Ecj7gnX76P8YxpPEg==", "requires": { - "@types/glob": "^7.1.1", "array-union": "^2.1.0", "dir-glob": "^3.0.1", - "fast-glob": "^3.0.3", - "glob": "^7.1.3", - "ignore": "^5.1.1", - "merge2": "^1.2.3", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", "slash": "^3.0.0" } }, @@ -30152,14 +32621,15 @@ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz", "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==" }, - "import-fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", - "requires": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" - } + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" + }, + "irregular-plurals": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-3.2.0.tgz", + "integrity": "sha512-YqTdPLfwP7YFN0SsD3QUVCkm9ZG2VzOXv3DOrw5G5mkMbVwptTwVcFv7/C0vOpBmgTxAeTG19XpUs1E522LW9Q==" }, "is-glob": { "version": "4.0.1", @@ -30175,9 +32645,22 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, "is-plain-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.0.0.tgz", - "integrity": "sha512-EYisGhpgSCwspmIuRHGjROWTon2Xp8Z7U03Wubk/bTL5TTRC5R1rGVgyjzBrk9+ULdH6cRD06KRcw/xfqhVYKQ==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==" + }, + "jsonc-parser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-2.2.1.tgz", + "integrity": "sha512-o6/yDBYccGvTz1+QFevz6l6OBZ2+fMVu2JZ9CIhzsYRX4mjaK5IyX9eldUdCmga16zlgQxyrj5pt9kzuj2C02w==" + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "requires": { + "p-locate": "^4.1.0" + } }, "log-symbols": { "version": "3.0.0", @@ -30185,8 +32668,48 @@ "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", "requires": { "chalk": "^2.4.2" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } + } + }, + "map-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.1.0.tgz", + "integrity": "sha512-glc9y00wgtwcDmp7GaE/0b0OnxpNJsVf3ael/An6Fe2Q51LLwN1er6sdomLRzz5h0+yMpiYLhWYF5R7HeqVd4g==" + }, + "meow": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-6.1.0.tgz", + "integrity": "sha512-iIAoeI01v6pmSfObAAWFoITAA4GgiT45m4SmJgoxtZfvI0fyZwhV4d0lTwiUXvAKIPlma05Feb2Xngl52Mj5Cg==", + "requires": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.1.1", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.0.0", + "minimist-options": "^4.0.1", + "normalize-package-data": "^2.5.0", + "read-pkg-up": "^7.0.0", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.8.1", + "yargs-parser": "^18.1.1" } }, + "merge2": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.3.0.tgz", + "integrity": "sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==" + }, "micromatch": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", @@ -30196,39 +32719,177 @@ "picomatch": "^2.0.5" } }, + "minimist-options": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.0.2.tgz", + "integrity": "sha512-seq4hpWkYSUh1y7NXxzucwAN9yVlBc3Upgdjz8vLCP97jG8kaOmzYrVH/m7tQ1NYD1wdtZbSLfdy4zFmRWuc/w==", + "requires": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0" + }, + "dependencies": { + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=" + } + } + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", + "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", "requires": { + "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" + "json-parse-better-errors": "^1.0.1", + "lines-and-columns": "^1.1.6" } }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + }, "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==" + }, + "plur": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/plur/-/plur-4.0.0.tgz", + "integrity": "sha512-4UGewrYgqDFw9vV6zNV+ADmPAUAfJPKtGvb/VdpQAx25X5f3xXdGdyOEVFwkl8Hl/tl7+xbeHqSEM+D5/TirUg==", + "requires": { + "irregular-plurals": "^3.2.0" + } + }, + "quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==" + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==" + } + } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + } + }, + "redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "requires": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + } + }, + "resolve": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", + "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", + "requires": { + "path-parse": "^1.0.6" + } + }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==" }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" }, + "strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "requires": { + "min-indent": "^1.0.0" + } + }, "strip-json-comments": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", - "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.0.tgz", + "integrity": "sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w==" }, "to-regex-range": { "version": "5.0.1", @@ -30237,6 +32898,25 @@ "requires": { "is-number": "^7.0.0" } + }, + "trim-newlines": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.0.tgz", + "integrity": "sha512-C4+gOpvmxaSMKuEf9Qc134F1ZuOHVXKRbtEflf4NTtuuJDEIJ9p5PXsalL8SkeRw+qit1Mo+yuvMPAKwWg/1hA==" + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" + }, + "yargs-parser": { + "version": "18.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.2.tgz", + "integrity": "sha512-hlIPNR3IzC1YuL1c2UwwDKpXlNFBqD1Fswwh1khz5+d8Cq/8yc/Mn0i+rQXduu8hcrFKvO7Eryk+09NecTQAAQ==", + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } } } }, @@ -30310,6 +32990,11 @@ "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, + "nwsapi": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==" + }, "oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", @@ -30409,15 +33094,11 @@ "has": "^1.0.1" } }, - "object.entries-ponyfill": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.entries-ponyfill/-/object.entries-ponyfill-1.0.1.tgz", - "integrity": "sha1-Kavfd8v70mVm3RqiTp2I9lQz0lY=" - }, "object.fromentries": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.0.tgz", "integrity": "sha512-9iLiI6H083uiqUuvzyY6qrlmc/Gz8hLQFOcb/Ri/0xXFkSNS3ctV+CbE6yM2+AnkYfOB3dGjdzC0wrMLIhQICA==", + "dev": true, "requires": { "define-properties": "^1.1.2", "es-abstract": "^1.11.0", @@ -30511,6 +33192,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, "requires": { "minimist": "~0.0.1", "wordwrap": "~0.0.2" @@ -30519,12 +33201,14 @@ "minimist": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", + "dev": true }, "wordwrap": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true } } }, @@ -30567,6 +33251,17 @@ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, "cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -30690,6 +33385,11 @@ "os-tmpdir": "^1.0.0" } }, + "p-cancelable": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.0.0.tgz", + "integrity": "sha512-wvPXDmbMmu2ksjkB4Z3nZWTSkJEb9lqVdMaCKpZUGJG9TMiNp9XcbG3fn9fPKjem04fJMJnXoyFPk2FmgiaiNg==" + }, "p-defer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", @@ -30699,10 +33399,19 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=", + "dev": true, "requires": { "p-reduce": "^1.0.0" } }, + "p-event": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.1.0.tgz", + "integrity": "sha512-4vAd06GCsgflX4wHN1JqrMzBh/8QZ4j+rzp0cd2scXRwuBEv+QR3wrVA5aLhWDLw4y2WgDKvzWF3CCLmVM1UgA==", + "requires": { + "p-timeout": "^2.0.1" + } + }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", @@ -30765,7 +33474,16 @@ "p-reduce": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", - "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=" + "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", + "dev": true + }, + "p-timeout": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz", + "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==", + "requires": { + "p-finally": "^1.0.0" + } }, "p-try": { "version": "1.0.0", @@ -30904,9 +33622,9 @@ "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" }, "patch-package": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/patch-package/-/patch-package-6.2.1.tgz", - "integrity": "sha512-dfCtQor63PPij6DDYtCzBRoO5nNAcMSg7Cmh+DLhR+s3t0OLQBdvFxJksZHBe1J2MjsSWDjTF4+oQKFbdkssIg==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/patch-package/-/patch-package-6.2.2.tgz", + "integrity": "sha512-YqScVYkVcClUY0v8fF0kWOjDYopzIM8e3bj/RU1DPeEF14+dCGm6UeOYm4jvCyxqIEQ5/eJzmbWfDWnUleFNMg==", "requires": { "@yarnpkg/lockfile": "^1.1.0", "chalk": "^2.4.2", @@ -30922,6 +33640,16 @@ "tmp": "^0.0.33" }, "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -31174,14 +33902,6 @@ } } }, - "plur": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/plur/-/plur-3.1.1.tgz", - "integrity": "sha512-t1Ax8KUvV3FFII8ltczPn2tJdjqbd1sIzu6t4JL7nQ3EyeL/lTrj5PWKb06ic5/6XYDr65rQ4uzQEGN70/6X5w==", - "requires": { - "irregular-plurals": "^2.0.0" - } - }, "pn": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", @@ -31270,6 +33990,26 @@ "supports-color": "^6.1.0" }, "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -31343,6 +34083,19 @@ "chalk": "^2.4.1", "source-map": "^0.6.1", "supports-color": "^5.4.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } } }, "source-map": { @@ -31899,6 +34652,18 @@ "lodash": "^4.17.11", "log-symbols": "^2.2.0", "postcss": "^7.0.7" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } } }, "postcss-resolve-nested-selector": { @@ -32033,6 +34798,24 @@ "react-is": "^16.8.4" }, "dependencies": { + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@types/yargs": { + "version": "13.0.8", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz", + "integrity": "sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA==", + "requires": { + "@types/yargs-parser": "*" + } + }, "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", @@ -32342,12 +35125,12 @@ } }, "prompts": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.3.0.tgz", - "integrity": "sha512-NfbbPPg/74fT7wk2XYQ7hAIp9zJyZp5Fu19iRbORqqy1BhtrkZ0fPafBU+7bmn8ie69DpT0R6QpJIN2oisYjJg==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.3.1.tgz", + "integrity": "sha512-qIP2lQyCwYbdzcqHIUi2HAxiWixhoM9OdLCWf8txXsapC/X9YdsCoeyRIXE/GP+Q0J37Q7+XN/MFqbUa7IzXNA==", "requires": { "kleur": "^3.0.3", - "sisteransi": "^1.0.3" + "sisteransi": "^1.0.4" } }, "promzard": { @@ -32379,6 +35162,12 @@ "reflect.ownkeys": "^0.2.0" } }, + "propagate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz", + "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==", + "dev": true + }, "property-information": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.3.0.tgz", @@ -32419,9 +35208,9 @@ } }, "proxy-from-env": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", - "integrity": "sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, "prr": { "version": "1.0.1", @@ -32650,58 +35439,196 @@ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, "puppeteer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-2.0.0.tgz", - "integrity": "sha512-t3MmTWzQxPRP71teU6l0jX47PHXlc4Z52sQv4LJQSZLq1ttkKS2yGM3gaI57uQwZkNaoGd0+HPPMELZkcyhlqA==", + "version": "npm:puppeteer-core@3.0.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-3.0.0.tgz", + "integrity": "sha512-oWjZFGMc0q2ak+8OxdmMffS79LIT0UEtmpV4h1/AARvESIqqKljf8mrfP+dQ2kas7XttsAZIxRBuWu7Y5JH8KQ==", + "dev": true, "requires": { + "@types/mime-types": "^2.1.0", "debug": "^4.1.0", - "extract-zip": "^1.6.6", - "https-proxy-agent": "^3.0.0", + "extract-zip": "^2.0.0", + "https-proxy-agent": "^4.0.0", "mime": "^2.0.3", + "mime-types": "^2.1.25", "progress": "^2.0.1", "proxy-from-env": "^1.0.0", - "rimraf": "^2.6.1", - "ws": "^6.1.0" + "rimraf": "^3.0.2", + "tar-fs": "^2.0.0", + "unbzip2-stream": "^1.3.3", + "ws": "^7.2.3" }, "dependencies": { + "agent-base": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz", + "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==", + "dev": true + }, + "bl": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.2.tgz", + "integrity": "sha512-j4OH8f6Qg2bGuWfRiltT2HYGx0e1QcBTrK9KAHNMwMZdQnDZFk0ZSYIpADjYCB3U12nicC5tVJwSIhwOWjb4RQ==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + } + } + }, + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, "debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, "requires": { "ms": "^2.1.1" } }, + "extract-zip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.0.tgz", + "integrity": "sha512-i42GQ498yibjdvIhivUsRslx608whtGoFIhF26Z7O4MYncBxp8CwalOs1lnHy21A9sIohWO2+uiE4SRtC9JXDg==", + "dev": true, + "requires": { + "@types/yauzl": "^2.9.1", + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + } + }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "dev": true, + "requires": { + "pend": "~1.2.0" + } + }, + "get-stream": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", + "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, "https-proxy-agent": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-3.0.1.tgz", - "integrity": "sha512-+ML2Rbh6DAuee7d07tYGEKOEi2voWPUGan+ExdPbPW6Z3svq+JCqr0v8WmKPOkz1vOVykPCBSuobe7G8GJUtVg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz", + "integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==", + "dev": true, "requires": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "requires": { - "ms": "^2.1.1" - } - } + "agent-base": "5", + "debug": "4" + } + }, + "mime-db": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", + "dev": true + }, + "mime-types": { + "version": "2.1.27", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "dev": true, + "requires": { + "mime-db": "1.44.0" } }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "tar-fs": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.1.tgz", + "integrity": "sha512-6tzWDMeroL87uF/+lin46k+Q+46rAJ0SyPGz7OW7wTgblI273hsBqk2C1j0/xNadNLKDTUL9BukSjB7cwgmlPA==", + "dev": true, + "requires": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.0.0" + } + }, + "tar-stream": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.2.tgz", + "integrity": "sha512-UaF6FoJ32WqALZGOIAApXx+OdxhekNMChu6axLJR85zMMjXKWFGjbIRe+J6P4UnRGg9rAwWvbTT0oI7hD/Un7Q==", + "dev": true, + "requires": { + "bl": "^4.0.1", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + } }, "ws": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", - "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.5.tgz", + "integrity": "sha512-C34cIU4+DB2vMyAbmEKossWq2ZQDr6QEyuuCzWrM9zfw1sGc0mYiJ0UnG9zzNykt49C2Fi34hvr2vssFQRS6EA==", + "dev": true + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "dev": true, "requires": { - "async-limiter": "~1.0.0" + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" } } } @@ -33024,6 +35951,17 @@ "node-releases": "^1.1.29" } }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -33349,6 +36287,19 @@ "chalk": "^2.0.0", "esutils": "^2.0.2", "js-tokens": "^4.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } } }, "@babel/parser": { @@ -33642,6 +36593,16 @@ "whatwg-fetch": "^3.0.0" }, "dependencies": { + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, "@react-native-community/cli": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-3.0.4.tgz", @@ -33687,6 +36648,16 @@ "ws": "^1.1.0" }, "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, "commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -33882,6 +36853,24 @@ } } }, + "@types/yargs": { + "version": "13.0.8", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz", + "integrity": "sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, "chardet": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", @@ -34066,6 +37055,16 @@ "through": "^2.3.6" }, "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", @@ -34084,6 +37083,47 @@ "number-is-nan": "^1.0.0" } }, + "jest-validate": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.9.0.tgz", + "integrity": "sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ==", + "requires": { + "@jest/types": "^24.9.0", + "camelcase": "^5.3.1", + "chalk": "^2.0.1", + "jest-get-type": "^24.9.0", + "leven": "^3.1.0", + "pretty-format": "^24.9.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "pretty-format": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", + "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", + "requires": { + "@jest/types": "^24.9.0", + "ansi-regex": "^4.0.0", + "ansi-styles": "^3.2.0", + "react-is": "^16.8.4" + } + } + } + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" + }, "load-json-file": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", @@ -34281,6 +37321,18 @@ "log-symbols": "^2.2.0", "strip-ansi": "^5.2.0", "wcwidth": "^1.0.1" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } } }, "p-limit": { @@ -34404,6 +37456,29 @@ } } }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + }, + "dependencies": { + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, "rxjs": { "version": "5.5.12", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.12.tgz", @@ -34549,6 +37624,14 @@ } } }, + "react-native-get-random-values": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/react-native-get-random-values/-/react-native-get-random-values-1.4.0.tgz", + "integrity": "sha512-NnmEZcC5zfz+QEytFPM/fw818Hodw/BNbv7jGxU4pla4K2K9DCzG83IReMJqQ2wo552AYKguqrBG2SSn/U6rbA==", + "requires": { + "fast-base64-decode": "^1.0.0" + } + }, "react-native-hr": { "version": "git+https://github.com/Riglerr/react-native-hr.git#2d01a5cf77212d100e8b99e0310cce5234f977b3", "from": "git+https://github.com/Riglerr/react-native-hr.git#2d01a5cf77212d100e8b99e0310cce5234f977b3" @@ -34696,12 +37779,10 @@ } }, "react-native-video": { - "version": "git+https://github.com/wordpress-mobile/react-native-video.git#c43bdf6b06d361da399b98b8d2e32b578fa188ac", - "from": "git+https://github.com/wordpress-mobile/react-native-video.git#c43bdf6b06d361da399b98b8d2e32b578fa188ac", + "version": "git+https://github.com/wordpress-mobile/react-native-video.git#6cdaddd9c81ebe2da5b28412d389cc105e156948", + "from": "git+https://github.com/wordpress-mobile/react-native-video.git#6cdaddd9c81ebe2da5b28412d389cc105e156948", "requires": { - "keymirror": "^0.1.1", - "prop-types": "^15.5.10", - "shaka-player": "^2.4.4" + "prop-types": "^15.5.10" } }, "react-outside-click-handler": { @@ -35093,37 +38174,43 @@ } }, "reakit": { - "version": "1.0.0-beta.12", - "resolved": "https://registry.npmjs.org/reakit/-/reakit-1.0.0-beta.12.tgz", - "integrity": "sha512-jf/0RWmJypG9wFbbCSj9mFxb474TCFnAweKnrh3yLJiMjKDEAFXic0cNyhqxSuOUUyZeT67bUFbu25DXBNfRmQ==", + "version": "1.0.0-rc.0", + "resolved": "https://registry.npmjs.org/reakit/-/reakit-1.0.0-rc.0.tgz", + "integrity": "sha512-jG9RfLE9DX3XP6xiUmindu8dJmd4rLs+ohQ2xppF9LVYQ/7Qa9B4kz8mNYbe42u8muE3nMM78T2RfXz+c/ZMsQ==", "requires": { + "@popperjs/core": "^2.1.0", "body-scroll-lock": "^2.6.4", - "popper.js": "^1.16.0", - "reakit-system": "^0.7.0", - "reakit-utils": "^0.7.1" - }, - "dependencies": { - "popper.js": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.0.tgz", - "integrity": "sha512-+G+EkOPoE5S/zChTpmBSSDYmhXJ5PsW8eMhH8cP/CQHMFPBG/kC9Y5IIw6qNYgdJ+/COf0ddY2li28iHaZRSjw==" - } + "reakit-system": "^0.10.0", + "reakit-utils": "^0.10.0", + "reakit-warning": "^0.1.0" } }, "reakit-system": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/reakit-system/-/reakit-system-0.7.0.tgz", - "integrity": "sha512-6MaQsoyIhU0b0RGfIfGSSGujCx0XVBtfJkRcn+TviiWwMXGS9liTCDBE1vn7fLnUYiR6kqll50Nmw//oIn97cg==" + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/reakit-system/-/reakit-system-0.10.0.tgz", + "integrity": "sha512-73ZI50NB2A6WAF3OsPJEEz73fax5cFiMoGMx3KxPT/AcS39rPqlBW6QkawtZC1HUebQXlsLxwZWicoFt8UubmQ==", + "requires": { + "reakit-utils": "^0.10.0" + } }, "reakit-utils": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/reakit-utils/-/reakit-utils-0.7.1.tgz", - "integrity": "sha512-xQJctof9V+wkC7OxSL7P14d5Se6l/apCfhY8liIfVihtakzXOkvKea4Ka/TbEfpoTKN7MRO4xNMxjfzuGFexHQ==" + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/reakit-utils/-/reakit-utils-0.10.0.tgz", + "integrity": "sha512-s1+nqLYrHo54U38iETdY86+VD+CZBTqF9rxMmphuft1Iz1i+L+OqOVJMq5sviBkTiEz8zRMhrNLcjBERFiPnkA==" + }, + "reakit-warning": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/reakit-warning/-/reakit-warning-0.1.0.tgz", + "integrity": "sha512-nfujYGWoZ1lh6eAFTVQc2aNjrAEf30PHffJw8Q8tiJJY4Knoy7eLA4jQGHTl3gOjhA9+Yd8KSmiLoOPlr6A0kA==", + "requires": { + "reakit-utils": "^0.10.0" + } }, "realpath-native": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz", "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==", + "dev": true, "requires": { "util.promisify": "^1.0.0" } @@ -35237,11 +38324,28 @@ "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==" }, + "regenerate-unicode-properties": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", + "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", + "requires": { + "regenerate": "^1.4.0" + } + }, "regenerator-runtime": { "version": "0.13.2", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz", "integrity": "sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA==" }, + "regenerator-transform": { + "version": "0.14.4", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.4.tgz", + "integrity": "sha512-EaJaKPBI9GvKpvUz2mz4fhx7WPgvwRLY9v3hlNHWmAuJHI13T4nwKnNvm5RWJzEdnI5g5UwtOww+S8IdoUC2bw==", + "requires": { + "@babel/runtime": "^7.8.4", + "private": "^0.1.8" + } + }, "regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", @@ -35255,7 +38359,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", - "dev": true, "requires": { "define-properties": "^1.1.3", "es-abstract": "^1.17.0-next.1" @@ -35265,7 +38368,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, "requires": { "object-keys": "^1.0.12" } @@ -35274,7 +38376,6 @@ "version": "1.17.4", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz", "integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==", - "dev": true, "requires": { "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", @@ -35292,8 +38393,7 @@ "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" } } }, @@ -35301,7 +38401,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, "requires": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -35311,20 +38410,17 @@ "has-symbols": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" }, "is-callable": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", - "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", - "dev": true + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==" }, "is-regex": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", - "dev": true, "requires": { "has": "^1.0.3" } @@ -35333,7 +38429,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "dev": true, "requires": { "has-symbols": "^1.0.1" } @@ -35341,14 +38436,12 @@ "object-inspect": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", - "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", - "dev": true + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==" }, "string.prototype.trimleft": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", - "dev": true, "requires": { "define-properties": "^1.1.3", "function-bind": "^1.1.1" @@ -35358,7 +38451,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", - "dev": true, "requires": { "define-properties": "^1.1.3", "function-bind": "^1.1.1" @@ -35371,20 +38463,33 @@ "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==" }, + "regexpu-core": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.0.tgz", + "integrity": "sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ==", + "requires": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.2.0", + "regjsgen": "^0.5.1", + "regjsparser": "^0.6.4", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.2.0" + } + }, "regextras": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/regextras/-/regextras-0.6.1.tgz", - "integrity": "sha512-EzIHww9xV2Kpqx+corS/I7OBmf2rZ0pKKJPsw5Dc+l6Zq1TslDmtRIP9maVn3UH+72MIXmn8zzDgP07ihQogUA==" + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/regextras/-/regextras-0.7.0.tgz", + "integrity": "sha512-ds+fL+Vhl918gbAUb0k2gVKbTZLsg84Re3DI6p85Et0U0tYME3hyW4nMK8Px4dtDaBA2qNjvG5uWyW7eK5gfmw==" }, "regjsgen": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.0.tgz", - "integrity": "sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA==" + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.1.tgz", + "integrity": "sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg==" }, "regjsparser": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz", - "integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==", + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.4.tgz", + "integrity": "sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==", "requires": { "jsesc": "~0.5.0" }, @@ -35548,6 +38653,19 @@ "chalk": "^2.0.0", "esutils": "^2.0.2", "js-tokens": "^4.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } } }, "@babel/parser": { @@ -35922,22 +39040,19 @@ "requires": { "mime-db": "1.40.0" } + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" } } }, - "request-progress": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", - "integrity": "sha1-TKdUCBx/7GP1BeT6qCWqBs1mnb4=", - "dev": true, - "requires": { - "throttleit": "^1.0.0" - } - }, "request-promise-core": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz", "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=", + "dev": true, "requires": { "lodash": "^4.13.1" } @@ -35946,6 +39061,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.5.tgz", "integrity": "sha1-UoF3D2jgyXGeUWP9P6tIIhX0/aU=", + "dev": true, "requires": { "request-promise-core": "1.1.1", "stealthy-require": "^1.1.0", @@ -36049,6 +39165,14 @@ "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" }, + "responselike": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz", + "integrity": "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==", + "requires": { + "lowercase-keys": "^2.0.0" + } + }, "restore-cursor": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", @@ -36102,11 +39226,26 @@ } }, "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "requires": { - "glob": "^7.0.5" + "glob": "^7.1.3" + }, + "dependencies": { + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } } }, "ripemd160": { @@ -36145,6 +39284,17 @@ "strip-json-comments": "^2.0.0" }, "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, "postcss": { "version": "6.0.23", "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", @@ -36219,6 +39369,7 @@ "version": "6.5.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.2.tgz", "integrity": "sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg==", + "dev": true, "requires": { "tslib": "^1.9.0" } @@ -36451,6 +39602,14 @@ "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, + "saxes": { + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-3.1.11.tgz", + "integrity": "sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g==", + "requires": { + "xmlchars": "^2.1.1" + } + }, "scheduler": { "version": "0.15.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.15.0.tgz", @@ -36642,14 +39801,6 @@ "safe-buffer": "^5.0.1" } }, - "shaka-player": { - "version": "2.5.10", - "resolved": "https://registry.npmjs.org/shaka-player/-/shaka-player-2.5.10.tgz", - "integrity": "sha512-kS9TQL6bWODo4XNnozERZWsEiWlLZ6huspPx4ZjmMjeOBL9gwqlULLfLyO+5gA3CYV/dk9LaAi1WAEaLWckGpA==", - "requires": { - "eme-encryption-scheme-polyfill": "^2.0.1" - } - }, "shallow-clone": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-1.0.0.tgz", @@ -36775,7 +39926,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.2.tgz", "integrity": "sha512-7rL9YlPHg7Ancea1S96Pa8/QWb4BtXL/TZvS6B8XFetGBeuhAsfmUspK6DokBeZ64+Kj9TCNRD/30pVz1BvQNA==", - "dev": true, "requires": { "es-abstract": "^1.17.0-next.1", "object-inspect": "^1.7.0" @@ -36785,7 +39935,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, "requires": { "object-keys": "^1.0.12" } @@ -36794,7 +39943,6 @@ "version": "1.17.4", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz", "integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==", - "dev": true, "requires": { "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", @@ -36813,7 +39961,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, "requires": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -36823,20 +39970,17 @@ "has-symbols": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" }, "is-callable": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", - "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", - "dev": true + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==" }, "is-regex": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", - "dev": true, "requires": { "has": "^1.0.3" } @@ -36845,7 +39989,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "dev": true, "requires": { "has-symbols": "^1.0.1" } @@ -36853,20 +39996,17 @@ "object-inspect": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", - "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", - "dev": true + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==" }, "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" }, "string.prototype.trimleft": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", - "dev": true, "requires": { "define-properties": "^1.1.3", "function-bind": "^1.1.1" @@ -36876,7 +40016,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", - "dev": true, "requires": { "define-properties": "^1.1.3", "function-bind": "^1.1.1" @@ -37220,9 +40359,9 @@ } }, "source-map-support": { - "version": "0.5.10", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.10.tgz", - "integrity": "sha512-YfQ3tQFTK/yzlGJuX8pTwa4tifQj4QS2Mj7UegOu8jAz59MqIiMGPXxQhVQiIMNzayuUSF/jEuVnfFF5JqybmQ==", + "version": "0.5.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.18.tgz", + "integrity": "sha512-9luZr/BZ2QeU6tO2uG8N2aZpVSli4TSAOAqFOyTO51AJcD9P99c0K1h6dD6r6qo5dyT44BR5exweOaLLeldTkQ==", "requires": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -37253,20 +40392,20 @@ "dev": true }, "spawnd": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/spawnd/-/spawnd-4.0.0.tgz", - "integrity": "sha512-ql3qhJnhAkvXpaqKBWOqou1rUTSQhFRaZkyOT+MTFB4xY3X+brgw6LTWV2wHuE9A6YPhrNe1cbg7S+jAYnbC0Q==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/spawnd/-/spawnd-4.4.0.tgz", + "integrity": "sha512-jLPOfB6QOEgMOQY15Z6+lwZEhH3F5ncXxIaZ7WHPIapwNNLyjrs61okj3VJ3K6tmP5TZ6cO0VAu9rEY4MD4YQg==", "requires": { "exit": "^0.1.2", "signal-exit": "^3.0.2", - "tree-kill": "^1.2.1", - "wait-port": "^0.2.2" + "tree-kill": "^1.2.2", + "wait-port": "^0.2.7" }, "dependencies": { "tree-kill": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.1.tgz", - "integrity": "sha512-4hjqbObwlh2dLyW4tcz0Ymw0ggoaVDMveUB9w8kFSQScdRLo0gxO9J7WFcUBo+W3C1TLdFIEwNOWebgZZ0RH9Q==" + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==" } } }, @@ -37486,12 +40625,27 @@ "dev": true }, "string-length": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", - "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-3.1.0.tgz", + "integrity": "sha512-Ttp5YvkGm5v9Ijagtaz1BnN+k9ObpvS0eIBblPMp2YWL8FBmi9qblQ9fexc2k/CXFgrTIteU3jAw3payCnwSTA==", "requires": { "astral-regex": "^1.0.0", - "strip-ansi": "^4.0.0" + "strip-ansi": "^5.2.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + } } }, "string-template": { @@ -37512,7 +40666,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.2.tgz", "integrity": "sha512-N/jp6O5fMf9os0JU3E72Qhf590RSRZU/ungsL/qJUYVTNv7hTG0P/dbPjxINVN9jpscu3nzYwKESU3P3RY5tOg==", - "dev": true, "requires": { "define-properties": "^1.1.3", "es-abstract": "^1.17.0", @@ -37526,7 +40679,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, "requires": { "object-keys": "^1.0.12" } @@ -37535,7 +40687,6 @@ "version": "1.17.4", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz", "integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==", - "dev": true, "requires": { "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", @@ -37553,8 +40704,7 @@ "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" } } }, @@ -37562,7 +40712,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, "requires": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -37572,20 +40721,17 @@ "has-symbols": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" }, "is-callable": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", - "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", - "dev": true + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==" }, "is-regex": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", - "dev": true, "requires": { "has": "^1.0.3" } @@ -37594,7 +40740,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "dev": true, "requires": { "has-symbols": "^1.0.1" } @@ -37602,14 +40747,12 @@ "object-inspect": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", - "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", - "dev": true + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==" }, "string.prototype.trimleft": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", - "dev": true, "requires": { "define-properties": "^1.1.3", "function-bind": "^1.1.1" @@ -37619,7 +40762,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", - "dev": true, "requires": { "define-properties": "^1.1.3", "function-bind": "^1.1.1" @@ -37858,13 +41000,214 @@ } }, "string.prototype.trim": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz", - "integrity": "sha1-0E3iyJ4Tf019IG8Ia17S+ua+jOo=", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.1.tgz", + "integrity": "sha512-MjGFEeqixw47dAMFMtgUro/I0+wNqZB5GKXGt1fFr24u3TzDXCPu7J9Buppzoe3r/LqkSDLDDJzE15RGWDGAVw==", "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.5.0", - "function-bind": "^1.0.2" + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1" + }, + "dependencies": { + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "requires": { + "object-keys": "^1.0.12" + } + }, + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + }, + "dependencies": { + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + } + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==" + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "requires": { + "has": "^1.0.3" + } + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "requires": { + "has-symbols": "^1.0.1" + } + }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==" + }, + "string.prototype.trimleft": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz", + "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimstart": "^1.0.0" + } + }, + "string.prototype.trimright": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz", + "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimend": "^1.0.0" + } + } + } + }, + "string.prototype.trimend": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.0.tgz", + "integrity": "sha512-EEJnGqa/xNfIg05SxiPSqRS7S9qwDhYts1TSLR1BQfYUfPe1stofgGKvwERK9+9yf+PpfBMlpBaCHucXGPQfUA==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + }, + "dependencies": { + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "requires": { + "object-keys": "^1.0.12" + } + }, + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + }, + "dependencies": { + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + } + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==" + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "requires": { + "has": "^1.0.3" + } + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "requires": { + "has-symbols": "^1.0.1" + } + }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==" + }, + "string.prototype.trimleft": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz", + "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimstart": "^1.0.0" + } + }, + "string.prototype.trimright": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz", + "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimend": "^1.0.0" + } + } } }, "string.prototype.trimleft": { @@ -37905,6 +41248,111 @@ } } }, + "string.prototype.trimstart": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.0.tgz", + "integrity": "sha512-iCP8g01NFYiiBOnwG1Xc3WZLyoo+RuBymwIlWncShXDDJYWN6DbnM3odslBJdgCdRlq94B5s63NWAZlcn2CS4w==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + }, + "dependencies": { + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "requires": { + "object-keys": "^1.0.12" + } + }, + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + }, + "dependencies": { + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + } + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==" + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "requires": { + "has": "^1.0.3" + } + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "requires": { + "has-symbols": "^1.0.1" + } + }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==" + }, + "string.prototype.trimleft": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz", + "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimstart": "^1.0.0" + } + }, + "string.prototype.trimright": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz", + "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimend": "^1.0.0" + } + } + } + }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -37959,8 +41407,7 @@ "strip-final-newline": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" }, "strip-indent": { "version": "2.0.0", @@ -38128,6 +41575,16 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, "debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", @@ -38276,7 +41733,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.0.0.tgz", "integrity": "sha512-bFhn0MQ8qefLyJ3K7PpHiPUTuTVPWw6RXfaMeV6xgJLXtBbszyboz1bvGTVv4R0YpQm2DqlXXn0fFHhxUHVE5w==", - "dev": true, "requires": { "has-flag": "^4.0.0", "supports-color": "^7.0.0" @@ -38285,14 +41741,12 @@ "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "supports-color": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, "requires": { "has-flag": "^4.0.0" } @@ -38331,6 +41785,17 @@ "util.promisify": "~1.0.0" }, "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, "css-select": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", @@ -38653,11 +42118,11 @@ } }, "tannin": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/tannin/-/tannin-1.1.0.tgz", - "integrity": "sha512-LxhcXqpMHEOVeVKmuG5aCPPsTXFlO373vrWkqN7FSJBVLS6lFOAg8ZGzIyGhrOf7Ho3xB4jdGedY1gi/8J1FCA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tannin/-/tannin-1.2.0.tgz", + "integrity": "sha512-U7GgX/RcSeUETbV7gYgoz8PD7Ni4y95pgIP/Z6ayI3CfhSujwKEBlGFTCRN+Aqnuyf4AN2yHL+L8x+TCGjb9uA==", "requires": { - "@tannin/plural-forms": "^1.0.3" + "@tannin/plural-forms": "^1.1.0" } }, "tapable": { @@ -38804,20 +42269,19 @@ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "dev": true + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true } } }, - "term-size": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.1.1.tgz", - "integrity": "sha512-UqvQSch04R+69g4RDhrslmGvGL3ucDRX/U+snYW0Mab4uCAyKSndUksaoqlJ81QKSpRnIsuOYQCbC2ZWx2896A==", - "dev": true - }, "terminal-link": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.0.0.tgz", "integrity": "sha512-rdBAY35jUvVapqCuhehjenLbYY73cVgRQ6podD6u9EDBomBBHjCOtmq2InPgPpTysOIOsQ5PdBzwSC/sKjv6ew==", - "dev": true, "requires": { "ansi-escapes": "^4.2.1", "supports-hyperlinks": "^2.0.0" @@ -38827,7 +42291,6 @@ "version": "4.2.1", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.2.1.tgz", "integrity": "sha512-Cg3ymMAdN10wOk/VYfLV7KCQyv7EDirJ64500sU7n9UlmioEtDuU5Gd+hj73hXSU/ex7tHJSssmyftDdkMLO8Q==", - "dev": true, "requires": { "type-fest": "^0.5.2" } @@ -38835,8 +42298,7 @@ "type-fest": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.5.2.tgz", - "integrity": "sha512-DWkS49EQKVX//Tbupb9TFa19c7+MK1XmzkrZUR8TAktmE/DizXoaoJV6TZ/tSIPXipqNiRI6CyAe7x69Jb6RSw==", - "dev": true + "integrity": "sha512-DWkS49EQKVX//Tbupb9TFa19c7+MK1XmzkrZUR8TAktmE/DizXoaoJV6TZ/tSIPXipqNiRI6CyAe7x69Jb6RSw==" } } }, @@ -39102,28 +42564,19 @@ } }, "test-exclude": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.2.tgz", - "integrity": "sha512-N2pvaLpT8guUpb5Fe1GJlmvmzH3x+DAKmmyEQmFP792QcLYoGE1syxztSvPD1V8yPe6VrcCt6YGQVjSRjCASsA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", "requires": { - "glob": "^7.1.3", - "minimatch": "^3.0.4", - "read-pkg-up": "^4.0.0", - "require-main-filename": "^2.0.0" + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" }, "dependencies": { - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "requires": { - "locate-path": "^3.0.0" - } - }, "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -39132,90 +42585,6 @@ "once": "^1.3.0", "path-is-absolute": "^1.0.0" } - }, - "load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", - "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" - }, - "read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - } - }, - "read-pkg-up": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", - "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", - "requires": { - "find-up": "^3.0.0", - "read-pkg": "^3.0.0" - } - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" } } }, @@ -39276,12 +42645,6 @@ "integrity": "sha512-AOvyNahXQuU7NN+VVvOOX+uW6FPaWdAOdRP5HfwYxAfCzXTFKRMoIMk+n+po318+ktcChx+F1Dd91G3YHeMKyg==", "dev": true }, - "throttleit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", - "integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=", - "dev": true - }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -39385,6 +42748,11 @@ } } }, + "to-readable-stream": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-2.1.0.tgz", + "integrity": "sha512-o3Qa6DGg1CEXshSdvWNX2sN4QHqg03SPq7U6jPXRahlQdl5dK8oXjkU/2/sGrnOZKeGV1zLSO8qPwyKklPPE7w==" + }, "to-regex": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", @@ -39554,6 +42922,14 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" }, + "tsutils": { + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", + "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", + "requires": { + "tslib": "^1.8.1" + } + }, "tty-browserify": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", @@ -39586,6 +42962,11 @@ "prelude-ls": "~1.1.2" } }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" + }, "type-fest": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", @@ -39626,10 +43007,18 @@ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } + }, "typescript": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz", - "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==", + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz", + "integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==", "dev": true }, "ua-parser-js": { @@ -39667,6 +43056,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz", "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==", + "dev": true, "optional": true, "requires": { "commander": "~2.20.0", @@ -39677,12 +43067,14 @@ "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, "optional": true }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, "optional": true } } @@ -39711,6 +43103,26 @@ "integrity": "sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0=", "dev": true }, + "unbzip2-stream": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.2.tgz", + "integrity": "sha512-pZMVAofMrrHX6Ik39hCk470kulCbmZ2SWfQLPmTWqfJV/oUm0gn1CblvHdUu4+54Je6Jq34x8kY6XjTy6dMkOg==", + "requires": { + "buffer": "^5.2.1", + "through": "^2.3.8" + }, + "dependencies": { + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + } + } + }, "underscore": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz", @@ -39746,9 +43158,9 @@ } }, "unicode-match-property-value-ecmascript": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz", - "integrity": "sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", + "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==" }, "unicode-property-aliases-ecmascript": { "version": "1.0.4", @@ -40121,15 +43533,40 @@ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.2.tgz", + "integrity": "sha512-vy9V/+pKG+5ZTYKf+VcphF5Oc6EFiu3W8Nv3P3zIh0EqVI80ZxOzuPfe9EHjkFNvf8+xuTHVeei4Drydlx4zjw==" }, "v8-compile-cache": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==" }, + "v8-to-istanbul": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-4.1.2.tgz", + "integrity": "sha512-G9R+Hpw0ITAmPSr47lSlc5A1uekSYzXxTMlFxso2xoffwo4jQnzbv1p9yXIinO8UMZKfAFewaCHwWvnH4Jb4Ug==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" + }, + "dependencies": { + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" + } + } + }, "validate-npm-package-license": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", @@ -40336,6 +43773,16 @@ "browser-process-hrtime": "^0.1.2" } }, + "w3c-xmlserializer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz", + "integrity": "sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg==", + "requires": { + "domexception": "^1.0.1", + "webidl-conversions": "^4.0.2", + "xml-name-validator": "^3.0.0" + } + }, "wait-on": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-3.3.0.tgz", @@ -40349,9 +43796,9 @@ }, "dependencies": { "core-js": { - "version": "2.6.10", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.10.tgz", - "integrity": "sha512-I39t74+4t+zau64EN1fE5v2W31Adtc/REhzWN+gWRRXg6WH5qAsZm62DHpQ1+Yhe4047T55jvzz7MUqF/dBBlA==" + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", + "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==" }, "rx": { "version": "4.1.0", @@ -40361,15 +43808,25 @@ } }, "wait-port": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/wait-port/-/wait-port-0.2.6.tgz", - "integrity": "sha512-nXE5Yp0Zs1obhFVc0Da7WVJc3y0LxoCq3j4mtV0NdI5P/ZvRdKp5yhuojvMOcOxSwpQL1hGbOgMNQ+4wpRpwCA==", + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/wait-port/-/wait-port-0.2.7.tgz", + "integrity": "sha512-pJ6cSBIa0w1sDg4y/wXN4bmvhM9OneOvwdFHo647L2NShBi/oXG4lRaLic5cO1HaYGbUhEvratPfl/WMlIC+tg==", "requires": { "chalk": "^2.4.2", "commander": "^3.0.2", "debug": "^4.1.1" }, "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, "commander": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", @@ -40564,6 +44021,16 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz", "integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==" }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, "commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -40599,6 +44066,26 @@ "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "cliui": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", @@ -40933,6 +44420,12 @@ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", "dev": true + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true } } }, @@ -40996,14 +44489,16 @@ "integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==" }, "whatwg-mimetype": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.1.0.tgz", - "integrity": "sha512-FKxhYLytBQiUKjkYteN71fAUA3g6KpNXoho1isLiLSB3N1G4F35Q5vUxWfKFhBwi5IWF27VE6WxhrnnC+m0Mew==" + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true }, "whatwg-url": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", + "dev": true, "requires": { "lodash.sortby": "^4.7.0", "tr46": "^1.0.1", @@ -41200,6 +44695,11 @@ } } }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" + }, "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", @@ -41370,6 +44870,13 @@ "requires": { "simple-plist": "^1.0.0", "uuid": "^3.3.2" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + } } }, "xml": { @@ -41388,6 +44895,11 @@ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=" }, + "xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" + }, "xmldoc": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/xmldoc/-/xmldoc-1.1.2.tgz", @@ -41406,6 +44918,14 @@ "resolved": "https://registry.npmjs.org/xpipe/-/xpipe-1.0.5.tgz", "integrity": "sha1-jdi/Rfw/f1Xw4FS4ePQ6YmFNr98=" }, + "xregexp": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.3.0.tgz", + "integrity": "sha512-7jXDIFXh5yJ/orPn4SXjuVrWWoi4Cr8jfV1eHv9CixKSbU+jY4mxfrBwAuDvupPNKpMUY+FeIqsVw/JLT9+B8g==", + "requires": { + "@babel/runtime-corejs3": "^7.8.3" + } + }, "xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", @@ -41589,6 +45109,7 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz", "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=", + "dev": true, "requires": { "fd-slicer": "~1.0.1" } diff --git a/package.json b/package.json index 93f7f0ff48e869..b193c250fb1d1b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gutenberg", - "version": "7.7.1", + "version": "7.9.1", "private": true, "description": "A new WordPress editor experience.", "author": "The WordPress Contributors", @@ -38,6 +38,7 @@ "@wordpress/deprecated": "file:packages/deprecated", "@wordpress/dom": "file:packages/dom", "@wordpress/dom-ready": "file:packages/dom-ready", + "@wordpress/edit-navigation": "file:packages/edit-navigation", "@wordpress/edit-post": "file:packages/edit-post", "@wordpress/edit-site": "file:packages/edit-site", "@wordpress/edit-widgets": "file:packages/edit-widgets", @@ -49,6 +50,7 @@ "@wordpress/html-entities": "file:packages/html-entities", "@wordpress/i18n": "file:packages/i18n", "@wordpress/icons": "file:packages/icons", + "@wordpress/interface": "file:packages/interface", "@wordpress/is-shallow-equal": "file:packages/is-shallow-equal", "@wordpress/keyboard-shortcuts": "file:packages/keyboard-shortcuts", "@wordpress/keycodes": "file:packages/keycodes", @@ -75,21 +77,27 @@ "devDependencies": { "@actions/core": "1.0.0", "@actions/github": "1.0.0", - "@babel/core": "7.8.3", + "@babel/core": "7.9.0", "@babel/plugin-syntax-jsx": "7.8.3", - "@babel/runtime-corejs3": "7.8.3", - "@babel/traverse": "7.8.3", + "@babel/runtime-corejs3": "7.9.2", + "@babel/traverse": "7.9.0", + "@jest/types": "25.3.0", "@octokit/rest": "16.26.0", "@octokit/webhooks": "7.1.0", "@storybook/addon-a11y": "5.3.2", "@storybook/addon-docs": "5.3.2", "@storybook/addon-knobs": "5.3.2", - "@storybook/addon-storyshots": "5.3.2", "@storybook/addon-storysource": "5.3.2", "@storybook/addon-viewport": "5.3.2", "@storybook/react": "5.3.2", - "@types/jest": "24.0.25", + "@testing-library/react": "10.0.2", + "@types/classnames": "2.2.10", + "@types/lodash": "4.14.149", + "@types/prettier": "1.19.0", + "@types/qs": "6.9.1", + "@types/react-dom": "16.9.5", "@types/requestidlecallback": "0.3.1", + "@types/sprintf-js": "1.1.2", "@wordpress/babel-plugin-import-jsx-pragma": "file:packages/babel-plugin-import-jsx-pragma", "@wordpress/babel-plugin-makepot": "file:packages/babel-plugin-makepot", "@wordpress/babel-preset-default": "file:packages/babel-preset-default", @@ -110,17 +118,18 @@ "@wordpress/npm-package-json-lint-config": "file:packages/npm-package-json-lint-config", "@wordpress/postcss-themes": "file:packages/postcss-themes", "@wordpress/prettier-config": "file:packages/prettier-config", + "@wordpress/project-management-automation": "file:packages/project-management-automation", "@wordpress/scripts": "file:packages/scripts", "babel-jest": "24.9.0", - "babel-loader": "8.0.6", - "babel-plugin-emotion": "10.0.27", + "babel-loader": "8.1.0", + "babel-plugin-emotion": "10.0.33", "babel-plugin-inline-json-import": "0.3.2", "babel-plugin-react-native-classname-to-style": "1.2.2", "babel-plugin-react-native-platform-specific-extensions": "1.1.1", "babel-plugin-require-context-hook": "1.0.0", "benchmark": "2.1.4", "browserslist": "4.9.1", - "chalk": "2.4.2", + "chalk": "4.0.0", "commander": "4.1.0", "concurrently": "3.5.0", "copy-webpack-plugin": "4.5.2", @@ -128,21 +137,22 @@ "css-loader": "3.2.0", "cssnano": "4.1.10", "deep-freeze": "0.0.1", - "enzyme": "3.9.0", + "enzyme": "3.11.0", "equivalent-key-map": "0.2.2", "eslint-plugin-eslint-comments": "3.1.2", - "eslint-plugin-import": "2.18.2", + "eslint-plugin-import": "2.20.2", + "execa": "4.0.0", "fast-glob": "2.2.7", "fbjs": "0.8.17", "glob": "7.1.2", "husky": "3.0.5", - "inquirer": "7.0.3", + "inquirer": "7.1.0", "is-equal-shallow": "0.1.3", "jest": "24.9.0", - "jest-emotion": "10.0.17", - "jest-junit": "6.4.0", + "jest-emotion": "10.0.32", + "jest-junit": "10.0.0", "jest-serializer-enzyme": "1.0.0", - "jsdom": "11.12.0", + "jsdom": "15.2.1", "lerna": "3.18.2", "lint-staged": "9.2.5", "lodash": "4.17.15", @@ -151,17 +161,19 @@ "metro-react-native-babel-preset": "0.57.0", "metro-react-native-babel-transformer": "0.56.0", "mkdirp": "0.5.1", + "nock": "12.0.3", "node-sass": "4.12.0", "node-watch": "0.6.0", "postcss": "7.0.13", "postcss-loader": "3.0.0", "prettier": "npm:wp-prettier@1.19.1", "progress": "2.0.3", + "puppeteer": "npm:puppeteer-core@3.0.0", "react": "16.9.0", "react-dom": "16.9.0", "react-native": "0.61.5", "react-test-renderer": "16.9.0", - "rimraf": "2.6.2", + "rimraf": "3.0.2", "rtlcss": "2.4.0", "sass-loader": "6.0.7", "semver": "6.0.0", @@ -173,16 +185,18 @@ "sprintf-js": "1.1.1", "style-loader": "1.0.0", "stylelint-config-wordpress": "13.1.0", - "typescript": "3.5.3", - "uuid": "3.3.2", + "typescript": "3.8.3", + "uuid": "7.0.2", "webpack": "4.42.0", "worker-farm": "1.7.0" }, "scripts": { "prebuild": "npm run check-engines", - "clean:packages": "rimraf ./packages/*/build ./packages/*/build-module ./packages/*/build-style ./packages/*/node_modules", + "clean:packages": "rimraf \"./packages/*/@(build|build-module|build-style)\"", + "clean:package-types": "tsc --build --clean", "prebuild:packages": "npm run clean:packages && lerna run build", - "build:packages": "node ./bin/packages/build.js", + "build:packages": "npm run build:package-types && node ./bin/packages/build.js", + "build:package-types": "node ./bin/packages/validate-typescript-version.js && tsc --build", "build": "npm run build:packages && wp-scripts build", "check-engines": "wp-scripts check-engines", "check-licenses": "concurrently \"wp-scripts check-licenses --prod --gpl2\" \"wp-scripts check-licenses --dev\"", @@ -191,20 +205,20 @@ "predev": "npm run check-engines", "dev": "npm run build:packages && concurrently \"wp-scripts start\" \"npm run dev:packages\"", "dev:packages": "node ./bin/packages/watch.js", - "docs:build": "node ./docs/tool/index.js && node ./bin/api-docs/update-readmes.js", + "docs:build": "node ./docs/tool/index.js && node ./bin/api-docs/update-api-docs.js", "fixtures:clean": "rimraf \"packages/e2e-tests/fixtures/blocks/*.+(json|serialized.html)\"", "fixtures:server-registered": "packages/env/bin/wp-env run wordpress ./wp-content/plugins/gutenberg/bin/get-server-blocks.php > test/integration/full-content/server-registered.json", "fixtures:generate": "npm run fixtures:server-registered && cross-env GENERATE_MISSING_FIXTURES=y npm run test-unit", "fixtures:regenerate": "npm run fixtures:clean && npm run fixtures:generate", "format-js": "wp-scripts format-js", - "lint": "concurrently \"npm run lint-js\" \"npm run lint-pkg-json\" \"npm run lint-css\" \"npm run lint-types\"", + "lint": "concurrently \"npm run lint-js\" \"npm run lint-pkg-json\" \"npm run lint-css\"", "lint-js": "wp-scripts lint-js", "lint-js:fix": "npm run lint-js -- --fix", + "prelint-php": "npm run wp-env run composer install -- --no-interaction", "lint-php": "npm run wp-env run composer run-script lint", "lint-pkg-json": "wp-scripts lint-pkg-json . 'packages/*/package.json'", "lint-css": "wp-scripts lint-style '**/*.scss'", "lint-css:fix": "npm run lint-css -- --fix", - "lint-types": "tsc", "lint:md-js": "wp-scripts lint-md-js", "lint:md-docs": "wp-scripts lint-md-docs", "native": "npm run --prefix packages/react-native-editor", @@ -215,9 +229,9 @@ "package-plugin": "./bin/build-plugin-zip.sh", "pot-to-php": "./bin/pot-to-php.js", "publish:check": "lerna updated", - "publish:dev": "npm run build:packages && lerna publish --dist-tag next", - "publish:legacy": "npm run build:packages && lerna publish --dist-tag legacy", - "publish:prod": "npm run build:packages && lerna publish", + "publish:dev": "npm run clean:package-types && npm run build:packages && lerna publish --dist-tag next", + "publish:legacy": "npm run clean:package-types && npm run build:packages && lerna publish --dist-tag legacy", + "publish:prod": "npm run clean:package-types && npm run build:packages && lerna publish", "test": "npm run lint && npm run test-unit", "test-e2e": "wp-scripts test-e2e --config packages/e2e-tests/jest.config.js", "test-e2e:watch": "npm run test-e2e -- --watch", @@ -248,6 +262,9 @@ } }, "lint-staged": { + "package-lock.json": [ + "node ./bin/check-latest-npm.js" + ], "packages/*/package.json": [ "wp-scripts lint-pkg-json" ], @@ -258,13 +275,13 @@ "wp-scripts format-js", "wp-scripts lint-js" ], - "{docs/{toc.json,tool/*.js},packages/{*/README.md,*/src/{actions,selectors}.js,components/src/*/**/README.md}}": [ - "node ./docs/tool/index.js", - "node ./docs/tool/are-data-files-unstaged.js" + "{docs/{toc.json,tool/*.js},packages/{*/README.md,components/src/*/**/README.md}}": [ + "node ./docs/tool/index.js" ], "packages/**/*.js": [ - "node ./bin/api-docs/update-readmes.js", - "node ./bin/api-docs/are-readmes-unstaged.js" + "node ./bin/api-docs/update-api-docs.js", + "node ./bin/api-docs/are-api-docs-unstaged.js", + "node ./bin/packages/lint-staged-typecheck.js" ] }, "wp-env": { diff --git a/packages/README.md b/packages/README.md index 30cccbed973c42..44162e64f69b23 100644 --- a/packages/README.md +++ b/packages/README.md @@ -7,46 +7,44 @@ This repository uses [lerna] to manage WordPress modules and publish them as pac When creating a new package, you need to provide at least the following: 1. `package.json` based on the template: - ```json - { - "name": "@wordpress/package-name", - "version": "1.0.0-beta.0", - "description": "Package description.", - "author": "The WordPress Contributors", - "license": "GPL-2.0-or-later", - "keywords": [ - "wordpress" - ], - "homepage": "https://github.com/WordPress/gutenberg/tree/master/packages/package-name/README.md", - "repository": { - "type": "git", - "url": "https://github.com/WordPress/gutenberg.git" - }, - "bugs": { - "url": "https://github.com/WordPress/gutenberg/issues" - }, - "main": "build/index.js", - "module": "build-module/index.js", - "react-native": "src/index", - "dependencies": { - "@babel/runtime": "^7.8.3" - }, - "publishConfig": { - "access": "public" - } - } - ``` - This assumes that your code is located in the `src` folder and will be transpiled with `Babel`. + ```json + { + "name": "@wordpress/package-name", + "version": "1.0.0-beta.0", + "description": "Package description.", + "author": "The WordPress Contributors", + "license": "GPL-2.0-or-later", + "keywords": [ "wordpress" ], + "homepage": "https://github.com/WordPress/gutenberg/tree/master/packages/package-name/README.md", + "repository": { + "type": "git", + "url": "https://github.com/WordPress/gutenberg.git" + }, + "bugs": { + "url": "https://github.com/WordPress/gutenberg/issues" + }, + "main": "build/index.js", + "module": "build-module/index.js", + "react-native": "src/index", + "dependencies": { + "@babel/runtime": "^7.9.2" + }, + "publishConfig": { + "access": "public" + } + } + ``` + This assumes that your code is located in the `src` folder and will be transpiled with `Babel`. 2. `.npmrc` file which disables creating `package-lock.json` file for the package: - ``` - package-lock=false - ``` + ``` + package-lock=false + ``` 3. `README.md` file containing at least: - - Package name - - Package description - - Installation details - - Usage example - - `Code is Poetry` logo (`

Code is Poetry.

`) + - Package name + - Package description + - Installation details + - Usage example + - `Code is Poetry` logo (`

Code is Poetry.

`) ## Managing Dependencies @@ -57,7 +55,7 @@ There are two types of dependencies that you might want to add to one of the exi Production dependencies are stored in the `dependencies` section of the package’s `package.json` file. #### Adding New Dependencies - + The simplest way to add a production dependency to one of the packages is to run a very convenient [lerna add](https://github.com/lerna/lerna/tree/master/commands/add#readme) command from the root of the project. _Example:_ @@ -79,9 +77,9 @@ _Example:_ @@ -43,7 +43,6 @@ "check-node-version": "^3.1.1", "cross-spawn": "^5.1.0", - "eslint": "^5.16.0", -- "jest": "^24.7.1", - "jest-puppeteer": "^4.0.0", + "eslint": "^6.8.0", +- "jest": "^25.3.0", + "jest-puppeteer": "^4.4.0", "minimist": "^1.2.0", "npm-package-json-lint": "^3.6.0", ``` @@ -93,7 +91,7 @@ Next, you need to run `npm install` in the root of the project to ensure that `p This is the most confusing part of working with [lerna] which causes a lot of hassles for contributors. The most successful strategy so far is to do the following: 1. First, remove the existing dependency as described in the previous section. 2. Next, add the same dependency back as described in the first section of this chapter. This time it wil get the latest version applied unless you enforce a different version explicitly. - + ### Development Dependencies In contrast to production dependencies, development dependencies shouldn't be stored in individual WordPress packages. Instead they should be installed in the project's `package.json` file using the usual `npm install` command. In effect, all development tools are configured to work with every package at the same time to ensure they share the same characteristics and integrate correctly with each other. @@ -119,16 +117,16 @@ _Example:_ ### Bug Fix -- Fixed an off-by-one error with the `sum` function. +- Fixed an off-by-one error with the `sum` function. ``` There are a number of common release subsections you can follow. Each is intended to align to a specific meaning in the context of the [Semantic Versioning (`semver`) specification](https://semver.org/) the project adheres to. It is important that you describe your changes accurately, since this is used in the packages release process to help determine the version of the next release. -- "Breaking Change" - A backwards-incompatible change which requires specific attention of the impacted developers to reconcile (requires a major version bump). -- "New Feature" - The addition of a new backwards-compatible function or feature to the existing public API (requires a minor verison bump). -- "Enhancement" - Backwards-compatible improvements to existing functionality (requires a minor version bump). -- "Bug Fix" - Resolutions to existing buggy behavior (requires a patch version bump). -- "Internal" - Changes which do not have an impact on the public interface or behavior of the module (requires a patch version bump). +- "Breaking Change" - A backwards-incompatible change which requires specific attention of the impacted developers to reconcile (requires a major version bump). +- "New Feature" - The addition of a new backwards-compatible function or feature to the existing public API (requires a minor verison bump). +- "Enhancement" - Backwards-compatible improvements to existing functionality (requires a minor version bump). +- "Bug Fix" - Resolutions to existing buggy behavior (requires a patch version bump). +- "Internal" - Changes which do not have an impact on the public interface or behavior of the module (requires a patch version bump). While other section naming can be used when appropriate, it's important that are expressed clearly to avoid confusion for both the packages releaser and third-party consumers. @@ -190,5 +188,61 @@ npm run publish:legacy This is usually necessary when adding bug fixes or security patches to the earlier versions of WordPress. +## TypeScript + +The [TypeScript](http://www.typescriptlang.org/) language is a typed superset of JavaScript that compiles to plain JavaScript. +Gutenberg does not use the TypeScript language, however TypeScript has powerful tooling that can be applied to JavaScript projects. + +Gutenberg uses TypeScript for several reasons, including: + +- Powerful editor integrations improve developer experience. +- Type system can detect some issues and lead to more robust software. +- Type declarations can be produced to allow other projects to benefit from these advantages as well. + +### Using TypeScript + +Gutenberg uses TypeScript by running the TypeScript compiler (`tsc`) on select packages. +These packages benefit from type checking and produced type declarations in the published packages. + +To opt-in to TypeScript tooling, packages should include a `tsconfig.json` file in the package root and add an entry to the root `tsconfig.json` references. +The changes will indicate that the package has opted-in and will be included in the TypeScript build process. + +A `tsconfig.json` file should look like the following (comments are not necessary): + +```jsonc +{ + // Extends a base configuration common to most packages + "extends": "../../tsconfig.base.json", + + // Options for the TypeScript compiler + // We'll usually set our `rootDir` and `declarationDir` as follows, which is specific + // to each project. + "compilerOptions": { + "rootDir": "src", + "declarationDir": "build-types" + }, + + // Which source files should be included + "include": [ "src/**/*" ], + + // Other WordPress package dependencies that have opted-in to TypeScript should be listed + // here. In this case, our package depends on `@wordpress/dom-ready`. + "references": [ { "path": "../dom-ready" } ] +} +``` + +Type declarations will be produced in the `build-types` which should be included in the published package. +For consumers to use the published type declarations, we'll set the `types` field in `package.json`: + +```json +{ + "main": "build/index.js", + "main-module": "build-module/index.js", + "types": "build-types" +} +``` + +Ensure that the `build-types` directory will be included in the published package, for example if a `files` field is declared. + [lerna]: https://lerna.js.org/ [npm]: https://www.npmjs.com/ diff --git a/packages/a11y/CHANGELOG.md b/packages/a11y/CHANGELOG.md index 6d3354f059cc82..872d37767d1b9b 100644 --- a/packages/a11y/CHANGELOG.md +++ b/packages/a11y/CHANGELOG.md @@ -1,3 +1,11 @@ +## Master + +## 2.9.0 (2020-04-15) + +### New feature + +- Include TypeScript type declarations ([#18942](https://github.com/WordPress/gutenberg/pull/18942)) + ## 2.0.0 (2018-09-05) ### Breaking Change diff --git a/packages/a11y/README.md b/packages/a11y/README.md index a45253197e7e6b..46cf83291fd301 100644 --- a/packages/a11y/README.md +++ b/packages/a11y/README.md @@ -23,7 +23,7 @@ Create the live regions. # **speak** Allows you to easily announce dynamic interface updates to screen readers using ARIA live regions. -This module is inspired by the `speak` function in wp-a11y.js +This module is inspired by the `speak` function in `wp-a11y.js`. _Usage_ @@ -39,15 +39,15 @@ speak( 'The message you want to send to the ARIA live region', 'assertive' ); _Parameters_ -- _message_ `string`: The message to be announced by Assistive Technologies. -- _ariaLive_ `string`: Optional. The politeness level for aria-live. Possible values: polite or assertive. Default polite. +- _message_ `string`: The message to be announced by assistive technologies. +- _ariaLive_ `[string]`: The politeness level for aria-live; default: 'polite'. ### Background -For context I'll quote [this article on WordPress.org](https://make.wordpress.org/accessibility/2015/04/15/let-wordpress-speak-new-in-wordpress-4-2/) by [@joedolson](https://github.com/joedolson): +For context I’ll quote [this article on WordPress.org](https://make.wordpress.org/accessibility/2015/04/15/let-wordpress-speak-new-in-wordpress-4-2/) by [@joedolson](https://github.com/joedolson): > #### Why. > @@ -71,4 +71,4 @@ For context I'll quote [this article on WordPress.org](https://make.wordpress.or See -

Code is Poetry.

+

Code is Poetry.

diff --git a/packages/a11y/package.json b/packages/a11y/package.json index 3f2dc80ae20901..fb9ca433bdd021 100644 --- a/packages/a11y/package.json +++ b/packages/a11y/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/a11y", - "version": "2.7.0", + "version": "2.9.0", "description": "Accessibility (a11y) utilities for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -21,8 +21,9 @@ "main": "build/index.js", "module": "build-module/index.js", "react-native": "src/index", + "types": "build-types", "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/dom-ready": "file:../dom-ready" }, "publishConfig": { diff --git a/packages/a11y/src/addContainer.js b/packages/a11y/src/add-container.js similarity index 72% rename from packages/a11y/src/addContainer.js rename to packages/a11y/src/add-container.js index edd733a6626a60..122adeaf8a15da 100644 --- a/packages/a11y/src/addContainer.js +++ b/packages/a11y/src/add-container.js @@ -1,15 +1,13 @@ /** * Build the live regions markup. * - * @param {string} ariaLive Optional. Value for the 'aria-live' attribute, default 'polite'. + * @param {string} [ariaLive] Value for the 'aria-live' attribute; default: 'polite'. * * @return {HTMLDivElement} The ARIA live region HTML element. */ -const addContainer = function( ariaLive ) { - ariaLive = ariaLive || 'polite'; - +export default function addContainer( ariaLive = 'polite' ) { const container = document.createElement( 'div' ); - container.id = 'a11y-speak-' + ariaLive; + container.id = `a11y-speak-${ ariaLive }`; container.className = 'a11y-speak-region'; container.setAttribute( @@ -30,12 +28,10 @@ const addContainer = function( ariaLive ) { container.setAttribute( 'aria-relevant', 'additions text' ); container.setAttribute( 'aria-atomic', 'true' ); - const body = document.querySelector( 'body' ); + const { body } = document; if ( body ) { body.appendChild( container ); } return container; -}; - -export default addContainer; +} diff --git a/packages/a11y/src/clear.js b/packages/a11y/src/clear.js index 94bab6ff853084..d4429a5394db2e 100644 --- a/packages/a11y/src/clear.js +++ b/packages/a11y/src/clear.js @@ -1,11 +1,10 @@ /** * Clear the a11y-speak-region elements. */ -const clear = function() { - const regions = document.querySelectorAll( '.a11y-speak-region' ); +export default function clear() { + const regions = document.getElementsByClassName( 'a11y-speak-region' ); + for ( let i = 0; i < regions.length; i++ ) { regions[ i ].textContent = ''; } -}; - -export default clear; +} diff --git a/packages/a11y/src/filterMessage.js b/packages/a11y/src/filter-message.js similarity index 89% rename from packages/a11y/src/filterMessage.js rename to packages/a11y/src/filter-message.js index 27a48e85fec98b..54fab7dec1aaa4 100644 --- a/packages/a11y/src/filterMessage.js +++ b/packages/a11y/src/filter-message.js @@ -7,7 +7,7 @@ let previousMessage = ''; * * @return {string} The filtered message. */ -const filterMessage = function( message ) { +export default function filterMessage( message ) { /* * Strip HTML tags (if any) from the message string. Ideally, messages should * be simple strings, carefully crafted for specific use with A11ySpeak. @@ -24,6 +24,4 @@ const filterMessage = function( message ) { previousMessage = message; return message; -}; - -export default filterMessage; +} diff --git a/packages/a11y/src/index.js b/packages/a11y/src/index.js index 97d10c65920202..cdd493091c2394 100644 --- a/packages/a11y/src/index.js +++ b/packages/a11y/src/index.js @@ -6,26 +6,26 @@ import domReady from '@wordpress/dom-ready'; /** * Internal dependencies */ -import addContainer from './addContainer'; +import addContainer from './add-container'; import clear from './clear'; -import filterMessage from './filterMessage'; +import filterMessage from './filter-message'; /** * Create the live regions. */ -export const setup = function() { - const containerPolite = document.getElementById( 'a11y-speak-polite' ); +export function setup() { const containerAssertive = document.getElementById( 'a11y-speak-assertive' ); + const containerPolite = document.getElementById( 'a11y-speak-polite' ); - if ( containerPolite === null ) { - addContainer( 'polite' ); - } if ( containerAssertive === null ) { addContainer( 'assertive' ); } -}; + if ( containerPolite === null ) { + addContainer( 'polite' ); + } +} /** * Run setup on domReady. @@ -34,11 +34,10 @@ domReady( setup ); /** * Allows you to easily announce dynamic interface updates to screen readers using ARIA live regions. - * This module is inspired by the `speak` function in wp-a11y.js + * This module is inspired by the `speak` function in `wp-a11y.js`. * - * @param {string} message The message to be announced by Assistive Technologies. - * @param {string} ariaLive Optional. The politeness level for aria-live. Possible values: - * polite or assertive. Default polite. + * @param {string} message The message to be announced by assistive technologies. + * @param {string} [ariaLive] The politeness level for aria-live; default: 'polite'. * * @example * ```js @@ -51,20 +50,20 @@ domReady( setup ); * speak( 'The message you want to send to the ARIA live region', 'assertive' ); * ``` */ -export const speak = function( message, ariaLive ) { +export function speak( message, ariaLive ) { // Clear previous messages to allow repeated strings being read out. clear(); message = filterMessage( message ); - const containerPolite = document.getElementById( 'a11y-speak-polite' ); const containerAssertive = document.getElementById( 'a11y-speak-assertive' ); + const containerPolite = document.getElementById( 'a11y-speak-polite' ); - if ( containerAssertive && 'assertive' === ariaLive ) { + if ( containerAssertive && ariaLive === 'assertive' ) { containerAssertive.textContent = message; } else if ( containerPolite ) { containerPolite.textContent = message; } -}; +} diff --git a/packages/a11y/src/index.native.js b/packages/a11y/src/index.native.js index 4e5e9841118b17..41a6591d34516f 100644 --- a/packages/a11y/src/index.native.js +++ b/packages/a11y/src/index.native.js @@ -1,19 +1,18 @@ /** * Internal dependencies */ -import filterMessage from './filterMessage'; +import filterMessage from './filter-message'; /** * Update the ARIA live notification area text node. * * @param {string} message The message to be announced by Assistive Technologies. - * @param {string} ariaLive Optional. The politeness level for aria-live. Possible values: - * polite or assertive. Default polite. + * @param {string} [ariaLive] The politeness level for aria-live; default: 'polite'. */ -export const speak = function( message, ariaLive ) { +export function speak( message, ariaLive ) { message = filterMessage( message ); //TODO: Use native module to speak message - if ( 'assertive' === ariaLive ) { + if ( ariaLive === 'assertive' ) { } else { } -}; +} diff --git a/packages/a11y/src/test/addContainer.test.js b/packages/a11y/src/test/add-container.test.js similarity index 91% rename from packages/a11y/src/test/addContainer.test.js rename to packages/a11y/src/test/add-container.test.js index 6ebf062237c9c0..c7e351dd38ef28 100644 --- a/packages/a11y/src/test/addContainer.test.js +++ b/packages/a11y/src/test/add-container.test.js @@ -1,14 +1,14 @@ /** * Internal dependencies */ -import addContainer from '../addContainer'; +import addContainer from '../add-container'; describe( 'addContainer', () => { describe( 'with polite param', () => { it( 'should create an aria-live element with aria-live attr set to polite', () => { const container = addContainer( 'polite' ); - expect( container ).not.toBe( null ); + expect( container ).not.toBeNull(); expect( container.className ).toBe( 'a11y-speak-region' ); expect( container.id ).toBe( 'a11y-speak-polite' ); expect( container.getAttribute( 'style' ) ).not.toBeNull(); @@ -24,7 +24,7 @@ describe( 'addContainer', () => { it( 'should create an aria-live element with aria-live attr set to assertive', () => { const container = addContainer( 'assertive' ); - expect( container ).not.toBe( null ); + expect( container ).not.toBeNull(); expect( container.className ).toBe( 'a11y-speak-region' ); expect( container.id ).toBe( 'a11y-speak-assertive' ); expect( container.getAttribute( 'style' ) ).not.toBeNull(); @@ -40,7 +40,7 @@ describe( 'addContainer', () => { it( 'should default to creating an aria-live element with aria-live attr set to polite', () => { const container = addContainer( 'polite' ); - expect( container ).not.toBe( null ); + expect( container ).not.toBeNull(); expect( container.className ).toBe( 'a11y-speak-region' ); expect( container.id ).toBe( 'a11y-speak-polite' ); expect( container.getAttribute( 'style' ) ).not.toBeNull(); diff --git a/packages/a11y/src/test/clear.test.js b/packages/a11y/src/test/clear.test.js index 02438dda1a4ecb..e45a45560c666f 100644 --- a/packages/a11y/src/test/clear.test.js +++ b/packages/a11y/src/test/clear.test.js @@ -8,12 +8,12 @@ describe( 'clear', () => { const container1 = document.createElement( 'div' ); container1.className = 'a11y-speak-region'; container1.textContent = 'not empty'; - document.querySelector( 'body' ).appendChild( container1 ); + document.body.appendChild( container1 ); const container2 = document.createElement( 'div' ); container2.className = 'a11y-speak-region'; container2.textContent = 'not empty'; - document.querySelector( 'body' ).appendChild( container2 ); + document.body.appendChild( container2 ); clear(); expect( container1.textContent ).toBe( '' ); diff --git a/packages/a11y/src/test/filterMessage.test.js b/packages/a11y/src/test/filter-message.test.js similarity index 88% rename from packages/a11y/src/test/filterMessage.test.js rename to packages/a11y/src/test/filter-message.test.js index 95302abb8d1ce2..9b0613ae72e3d5 100644 --- a/packages/a11y/src/test/filterMessage.test.js +++ b/packages/a11y/src/test/filter-message.test.js @@ -1,7 +1,7 @@ /** * Internal dependencies */ -import filterMessage from '../filterMessage'; +import filterMessage from '../filter-message'; describe( 'filterMessage', () => { describe( 'when a clean message is passed in', () => { @@ -15,7 +15,7 @@ describe( 'filterMessage', () => { it( 'should add a space to the message to make sure it is announced again', () => { filterMessage( 'repeated message.' ); const actual = filterMessage( 'repeated message.' ); - expect( actual ).toBe( 'repeated message.' + '\u00A0' ); + expect( actual ).toBe( 'repeated message.\u00A0' ); } ); } ); diff --git a/packages/a11y/src/test/index.test.js b/packages/a11y/src/test/index.test.js index 9888f9adb3a145..b17806c895353c 100644 --- a/packages/a11y/src/test/index.test.js +++ b/packages/a11y/src/test/index.test.js @@ -8,7 +8,7 @@ import domReady from '@wordpress/dom-ready'; */ import { setup, speak } from '../'; import clear from '../clear'; -import filterMessage from '../filterMessage'; +import filterMessage from '../filter-message'; jest.mock( '../clear', () => { return jest.fn(); @@ -18,7 +18,7 @@ jest.mock( '@wordpress/dom-ready', () => { callback(); } ); } ); -jest.mock( '../filterMessage', () => { +jest.mock( '../filter-message', () => { return jest.fn( ( message ) => { return message; } ); @@ -82,9 +82,9 @@ describe( 'speak', () => { it( 'should set the textcontent of the polite aria-live region', () => { speak( 'message', 'assertive' ); expect( containerPolite.textContent ).toBe( 'message' ); - expect( document.getElementById( 'a11y-speak-assertive' ) ).toBe( - null - ); + expect( + document.getElementById( 'a11y-speak-assertive' ) + ).toBeNull(); } ); } ); @@ -103,12 +103,10 @@ describe( 'speak', () => { } ); it( 'should set the textcontent of the polite aria-live region', () => { - expect( document.getElementById( 'a11y-speak-polite' ) ).toBe( - null - ); - expect( document.getElementById( 'a11y-speak-assertive' ) ).toBe( - null - ); + expect( document.getElementById( 'a11y-speak-polite' ) ).toBeNull(); + expect( + document.getElementById( 'a11y-speak-assertive' ) + ).toBeNull(); } ); } ); diff --git a/packages/a11y/tsconfig.json b/packages/a11y/tsconfig.json new file mode 100644 index 00000000000000..1a0a90bc8cb582 --- /dev/null +++ b/packages/a11y/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "src", + "declarationDir": "build-types" + }, + "references": [ { "path": "../dom-ready" } ], + "include": [ "src/**/*" ] +} diff --git a/packages/annotations/package.json b/packages/annotations/package.json index 903d268911414a..a7613b253c69b8 100644 --- a/packages/annotations/package.json +++ b/packages/annotations/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/annotations", - "version": "1.12.1", + "version": "1.14.1", "description": "Annotate content in the Gutenberg editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -21,14 +21,14 @@ "module": "build-module/index.js", "react-native": "src/index", "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/data": "file:../data", "@wordpress/hooks": "file:../hooks", "@wordpress/i18n": "file:../i18n", "@wordpress/rich-text": "file:../rich-text", "lodash": "^4.17.15", "rememo": "^3.0.0", - "uuid": "^3.3.2" + "uuid": "^7.0.2" }, "publishConfig": { "access": "public" diff --git a/packages/annotations/src/block/index.js b/packages/annotations/src/block/index.js index c27c170b2d64a1..3a5dee89607abc 100644 --- a/packages/annotations/src/block/index.js +++ b/packages/annotations/src/block/index.js @@ -11,7 +11,7 @@ import { withSelect } from '@wordpress/data'; * @return {Object} The enhanced component. */ const addAnnotationClassName = ( OriginalComponent ) => { - return withSelect( ( select, { clientId } ) => { + return withSelect( ( select, { clientId, className } ) => { const annotations = select( 'core/annotations' ).__experimentalGetAnnotationsForBlock( clientId ); @@ -21,6 +21,8 @@ const addAnnotationClassName = ( OriginalComponent ) => { .map( ( annotation ) => { return 'is-annotated-by-' + annotation.source; } ) + .concat( className ) + .filter( Boolean ) .join( ' ' ), }; } )( OriginalComponent ); diff --git a/packages/annotations/src/store/actions.js b/packages/annotations/src/store/actions.js index f5d5b8cf208e55..00c9fa589732af 100644 --- a/packages/annotations/src/store/actions.js +++ b/packages/annotations/src/store/actions.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import uuid from 'uuid/v4'; +import { v4 as uuid } from 'uuid'; /** * Adds an annotation to a block. diff --git a/packages/api-fetch/CHANGELOG.md b/packages/api-fetch/CHANGELOG.md index d89748053a6cfa..34d8c1b6dc521c 100644 --- a/packages/api-fetch/CHANGELOG.md +++ b/packages/api-fetch/CHANGELOG.md @@ -1,3 +1,8 @@ +## 3.8.1 (2019-04-22) + +- Added deprecation to `useApiFetch` hook. +- Added `@wordpress/deprecation` package to add deprecation notice to `useApiFetch` hook. + ## 3.8.0 (2019-12-19) ### Bug Fixes diff --git a/packages/api-fetch/package.json b/packages/api-fetch/package.json index 0e5f9c1a912b2e..670ee9f81ba807 100644 --- a/packages/api-fetch/package.json +++ b/packages/api-fetch/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/api-fetch", - "version": "3.11.0", + "version": "3.13.1", "description": "Utility to make WordPress REST API requests.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -22,7 +22,9 @@ "module": "build-module/index.js", "react-native": "src/index", "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", + "@wordpress/deprecated": "file:../deprecated", + "@wordpress/element": "file:../element", "@wordpress/i18n": "file:../i18n", "@wordpress/url": "file:../url" }, diff --git a/packages/api-fetch/src/index.js b/packages/api-fetch/src/index.js index 9e7edc985709ed..f16fe6c65b4d08 100644 --- a/packages/api-fetch/src/index.js +++ b/packages/api-fetch/src/index.js @@ -2,6 +2,8 @@ * WordPress dependencies */ import { __ } from '@wordpress/i18n'; +import { useEffect, useState } from '@wordpress/element'; +import deprecated from '@wordpress/deprecated'; /** * Internal dependencies @@ -156,6 +158,48 @@ function apiFetch( options ) { } ); } +/** + * Function that fetches data using apiFetch, and updates the status. + * + * @param {string} path Query path. + */ +function useApiFetch( path ) { + deprecated( 'useApiFetch', { + version: '8.1.0', + alternative: 'apiFetch', + plugin: 'Gutenberg', + } ); + + // Indicate the fetching status + const [ isLoading, setIsLoading ] = useState( true ); + const [ data, setData ] = useState( null ); + const [ error, setError ] = useState( null ); + + useEffect( () => { + setIsLoading( true ); + setData( null ); + setError( null ); + + apiFetch( { path } ) + .then( ( fetchedData ) => { + setData( fetchedData ); + // We've stopped fetching + setIsLoading( false ); + } ) + .catch( ( err ) => { + setError( err ); + // We've stopped fetching + setIsLoading( false ); + } ); + }, [ path ] ); + + return { + isLoading, + data, + error, + }; +} + apiFetch.use = registerMiddleware; apiFetch.setFetchHandler = setFetchHandler; @@ -165,4 +209,6 @@ apiFetch.createRootURLMiddleware = createRootURLMiddleware; apiFetch.fetchAllMiddleware = fetchAllMiddleware; apiFetch.mediaUploadMiddleware = mediaUploadMiddleware; +apiFetch.useApiFetch = useApiFetch; + export default apiFetch; diff --git a/packages/autop/CHANGELOG.md b/packages/autop/CHANGELOG.md index 0f40e07f861653..23c8689b2145c7 100644 --- a/packages/autop/CHANGELOG.md +++ b/packages/autop/CHANGELOG.md @@ -1,3 +1,11 @@ +## Master + +## 2.7.0 (2020-04-15) + +### New feature + +- Include TypeScript type declarations ([#20669](https://github.com/WordPress/gutenberg/pull/20669)) + ## 2.3.0 (2019-05-21) ### Bug Fix diff --git a/packages/autop/package.json b/packages/autop/package.json index 9a4f5d7fbaaacb..fc1bc1cdeb8e99 100644 --- a/packages/autop/package.json +++ b/packages/autop/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/autop", - "version": "2.6.0", + "version": "2.7.0", "description": "WordPress's automatic paragraph functions `autop` and `removep`.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -20,9 +20,10 @@ "main": "build/index.js", "module": "build-module/index.js", "react-native": "src/index", + "types": "build-types", "sideEffects": false, "dependencies": { - "@babel/runtime": "^7.8.3" + "@babel/runtime": "^7.9.2" }, "publishConfig": { "access": "public" diff --git a/packages/autop/src/index.js b/packages/autop/src/index.js index 3a0fc7fa73600e..b2c605620852f3 100644 --- a/packages/autop/src/index.js +++ b/packages/autop/src/index.js @@ -1,7 +1,7 @@ /** * The regular expression for an HTML element. * - * @type {string} + * @type {RegExp} */ const htmlSplitRegex = ( () => { /* eslint-disable no-multi-spaces */ @@ -52,7 +52,7 @@ const htmlSplitRegex = ( () => { * Separate HTML elements and comments from the text. * * @param {string} input The text which has to be formatted. - * @return {Array} The formatted text. + * @return {string[]} The formatted text. */ function htmlSplit( input ) { const parts = []; @@ -60,9 +60,15 @@ function htmlSplit( input ) { let match; while ( ( match = workingInput.match( htmlSplitRegex ) ) ) { - parts.push( workingInput.slice( 0, match.index ) ); + // The `match` result, when invoked on a RegExp with the `g` flag (`/foo/g`) will not include `index`. + // If the `g` flag is omitted, `index` is included. + // `htmlSplitRegex` does not have the `g` flag so we can assert it will have an index number. + // Assert `match.index` is a number. + const index = /** @type {number} */ ( match.index ); + + parts.push( workingInput.slice( 0, index ) ); parts.push( match[ 0 ] ); - workingInput = workingInput.slice( match.index + match[ 0 ].length ); + workingInput = workingInput.slice( index + match[ 0 ].length ); } if ( workingInput.length ) { @@ -75,9 +81,9 @@ function htmlSplit( input ) { /** * Replace characters or phrases within HTML elements only. * - * @param {string} haystack The text which has to be formatted. - * @param {Object} replacePairs In the form {from: 'to', ...}. - * @return {string} The formatted text. + * @param {string} haystack The text which has to be formatted. + * @param {Record} replacePairs In the form {from: 'to', …}. + * @return {string} The formatted text. */ function replaceInHtmlTags( haystack, replacePairs ) { // Find all elements. @@ -337,6 +343,7 @@ export function removep( html ) { 'blockquote|ul|ol|li|dl|dt|dd|table|thead|tbody|tfoot|tr|th|td|h[1-6]|fieldset|figure'; const blocklist1 = blocklist + '|div|p'; const blocklist2 = blocklist + '|pre'; + /** @type {string[]} */ const preserve = []; let preserveLinebreaks = false; let preserveBr = false; @@ -399,7 +406,7 @@ export function removep( html ) { html = html.replace( /\n[\s\u00a0]+\n/g, '\n\n' ); // Replace
tags with line breaks. - html = html.replace( /(\s*)
\s*/gi, function( match, space ) { + html = html.replace( /(\s*)
\s*/gi, function( _, space ) { if ( space && space.indexOf( '\n' ) !== -1 ) { return '\n\n'; } @@ -470,7 +477,7 @@ export function removep( html ) { // Restore preserved tags. if ( preserve.length ) { html = html.replace( //g, function() { - return preserve.shift(); + return /** @type {string} */ ( preserve.shift() ); } ); } diff --git a/packages/autop/tsconfig.json b/packages/autop/tsconfig.json new file mode 100644 index 00000000000000..1a0a90bc8cb582 --- /dev/null +++ b/packages/autop/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "src", + "declarationDir": "build-types" + }, + "references": [ { "path": "../dom-ready" } ], + "include": [ "src/**/*" ] +} diff --git a/packages/babel-plugin-makepot/package.json b/packages/babel-plugin-makepot/package.json index 2219269afd4b65..3412b1160796e7 100644 --- a/packages/babel-plugin-makepot/package.json +++ b/packages/babel-plugin-makepot/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/babel-plugin-makepot", - "version": "3.4.0", + "version": "3.5.0", "description": "WordPress Babel internationalization (i18n) plugin.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -29,7 +29,7 @@ "main": "build/index.js", "module": "build-module/index.js", "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "gettext-parser": "^1.3.1", "lodash": "^4.17.15" }, diff --git a/packages/babel-preset-default/CHANGELOG.md b/packages/babel-preset-default/CHANGELOG.md index 16bd181f83a302..808cc1302c123d 100644 --- a/packages/babel-preset-default/CHANGELOG.md +++ b/packages/babel-preset-default/CHANGELOG.md @@ -1,10 +1,16 @@ ## Master +## 4.12.0 (2020-04-15) + +### New Features + +- The bundled `@babel/core` dependency has been updated from requiring `^7.8.3` to requiring `^7.9.0`. All other Babel plugins were updated to the latest version (see [Highlights](https://babeljs.io/blog/2020/03/16/7.9.0)). + ## 4.10.0 (2020-02-04) ### New Feature -- The bundled `@babel/core` dependency has been updated from requiring `^7.4.4` to requiring `^7.8.3`. All other Babel plugins were updated to the latest version. `@babel/preset-env` has now ESMAScript 2020 support enabled by default (see [Highlights](https://babeljs.io/blog/2020/01/11/7.8.0#highlights)). +- The bundled `@babel/core` dependency has been updated from requiring `^7.4.4` to requiring `^7.8.3`. All other Babel plugins were updated to the latest version. `@babel/preset-env` has now ESMAScript 2020 support enabled by default (see [Highlights](https://babeljs.io/blog/2020/01/11/7.8.0#highlights)). ## 4.5.0 (2019-08-29) diff --git a/packages/babel-preset-default/index.js b/packages/babel-preset-default/index.js index 15454ecb36fd65..e331b212cd0ba8 100644 --- a/packages/babel-preset-default/index.js +++ b/packages/babel-preset-default/index.js @@ -58,7 +58,6 @@ module.exports = function( api ) { return { presets: [ getPresetEnv() ], plugins: [ - require.resolve( '@babel/plugin-proposal-object-rest-spread' ), require.resolve( '@wordpress/warning/babel-plugin' ), [ require.resolve( '@wordpress/babel-plugin-import-jsx-pragma' ), @@ -76,9 +75,6 @@ module.exports = function( api ) { pragmaFrag: 'Fragment', }, ], - require.resolve( - '@babel/plugin-proposal-async-generator-functions' - ), maybeGetPluginTransformRuntime(), ].filter( Boolean ), }; diff --git a/packages/babel-preset-default/package.json b/packages/babel-preset-default/package.json index 9661558f620a48..1cd59eb16d05bf 100644 --- a/packages/babel-preset-default/package.json +++ b/packages/babel-preset-default/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/babel-preset-default", - "version": "4.10.0", + "version": "4.12.1", "description": "Default Babel preset for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -27,18 +27,16 @@ ], "main": "index.js", "dependencies": { - "@babel/core": "^7.8.3", - "@babel/plugin-proposal-async-generator-functions": "^7.8.3", - "@babel/plugin-proposal-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-react-jsx": "^7.8.3", - "@babel/plugin-transform-runtime": "^7.8.3", - "@babel/preset-env": "^7.8.3", - "@babel/runtime": "^7.8.3", + "@babel/core": "^7.9.0", + "@babel/plugin-transform-react-jsx": "^7.9.4", + "@babel/plugin-transform-runtime": "^7.9.0", + "@babel/preset-env": "^7.9.0", + "@babel/runtime": "^7.9.2", "@wordpress/babel-plugin-import-jsx-pragma": "file:../babel-plugin-import-jsx-pragma", "@wordpress/browserslist-config": "file:../browserslist-config", "@wordpress/element": "file:../element", "@wordpress/warning": "file:../warning", - "core-js": "^3.1.4" + "core-js": "^3.6.4" }, "publishConfig": { "access": "public" diff --git a/packages/babel-preset-default/test/__snapshots__/index.js.snap b/packages/babel-preset-default/test/__snapshots__/index.js.snap index 58bfb14629a285..9f7b9d7e009d99 100644 --- a/packages/babel-preset-default/test/__snapshots__/index.js.snap +++ b/packages/babel-preset-default/test/__snapshots__/index.js.snap @@ -11,9 +11,7 @@ describe('Babel preset default', function () { } function _foo() { - _foo = _wrapAsyncGenerator( - /*#__PURE__*/ - _regeneratorRuntime.mark(function _callee() { + _foo = _wrapAsyncGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() { return _regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { @@ -35,11 +33,7 @@ describe('Babel preset default', function () { return _foo.apply(this, arguments); } - test('support for async generator functions', - /*#__PURE__*/ - _asyncToGenerator( - /*#__PURE__*/ - _regeneratorRuntime.mark(function _callee2() { + test('support for async generator functions', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() { var generator; return _regeneratorRuntime.wrap(function _callee2$(_context2) { while (1) { @@ -52,13 +46,12 @@ describe('Babel preset default', function () { case 4: _context2.t1 = _context2.sent; - _context2.t2 = { + (0, _context2.t0)(_context2.t1).toEqual({ done: false, value: 2 - }; - (0, _context2.t0)(_context2.t1).toEqual(_context2.t2); + }); - case 7: + case 6: case \\"end\\": return _context2.stop(); } diff --git a/packages/base-styles/_colors.native.scss b/packages/base-styles/_colors.native.scss index 3a6e9c3992e556..5c893c0a30685d 100644 --- a/packages/base-styles/_colors.native.scss +++ b/packages/base-styles/_colors.native.scss @@ -152,3 +152,4 @@ $gray-70: #3c434a; $gray-90: #1d2327; $gray-95: #1d2327; $gray-100: #101517; +$red-40: #e65054; diff --git a/packages/base-styles/_mixins.scss b/packages/base-styles/_mixins.scss index b97325fd9116ff..b2902274839e2a 100644 --- a/packages/base-styles/_mixins.scss +++ b/packages/base-styles/_mixins.scss @@ -114,124 +114,32 @@ } /** - * Button states and focus styles + * Focus styles. */ -// Buttons with rounded corners. -@mixin button-style__disabled { - opacity: 0.6; - cursor: default; -} - -@mixin button-style__active() { - outline: none; - background-color: $white; - color: $dark-gray-900; - box-shadow: inset 0 0 0 1px $light-gray-700, inset 0 0 0 2px $white; -} - -@mixin button-style__focus-active() { - box-shadow: 0 0 0 1px color($theme-color); - - // Windows High Contrast mode will show this outline, but not the box-shadow. - outline: 1px solid transparent; -} - -// Switch. -@mixin switch-style__focus-active() { - box-shadow: 0 0 0 2px $white, 0 0 0 3px $dark-gray-300; +@mixin block-toolbar-button-style__focus() { + box-shadow: inset 0 0 0 $border-width-focus $theme-color, inset 0 0 0 4px $white; // Windows High Contrast mode will show this outline, but not the box-shadow. outline: 2px solid transparent; - outline-offset: 2px; } - -/** - * Block Toolbar/Formatting Buttons - */ - -@mixin block-toolbar-button-style__focus() { - box-shadow: inset 0 0 0 2px color($theme-color), inset 0 0 0 4px $white; // Inner halo makes this work on top of a toggled button. - outline: 2px solid transparent; // Shown to Windows 10 High Contrast Mode. -} - - // Tabs, Inputs, Square buttons. @mixin input-style__neutral() { box-shadow: 0 0 0 transparent; transition: box-shadow 0.1s linear; - border-radius: $radius-round-rectangle; - border: $border-width solid $dark-gray-200; + border-radius: $radius-block-ui; + border: $border-width solid $medium-gray-text; @include reduce-motion("transition"); } -@mixin input-style__focus() { - color: $dark-gray-900; - border-color: $blue-medium-focus; - box-shadow: 0 0 0 1px $blue-medium-focus; - - // Windows High Contrast mode will show this outline, but not the box-shadow. - outline: 2px solid transparent; -} - -// Square buttons. -@mixin square-style__neutral() { - outline-offset: -1px; -} - -@mixin square-style__focus() { - color: $dark-gray-900; - outline-offset: -1px; - outline: 1px dotted $dark-gray-500; -} - -// Menu items. -@mixin menu-style__neutral() { - border: none; - box-shadow: none; -} - -@mixin menu-style__hover() { - color: $dark-gray-900; - border: none; - box-shadow: none; - background: $light-gray-200; -} - -@mixin menu-style__focus() { - color: $dark-gray-900; - border: none; - box-shadow: none; - outline-offset: -2px; - outline: 1px dotted $dark-gray-500; -} -// Blocks in the Library. -@mixin block-style__disabled { - opacity: 0.6; - cursor: default; -} - -@mixin block-style__hover { - border-color: $theme-color; - color: $theme-color !important; -} - -@mixin block-style__focus() { - box-shadow: inset 0 0 0 1px $white, 0 0 0 2px $theme-color; - - // Windows High Contrast mode will show this outline, but not the box-shadow. - outline: 2px solid transparent; -} - -@mixin block-style__is-active() { - color: $white; - background: $dark-gray-primary; +@mixin input-style__focus() { + border-color: color($theme-color); + box-shadow: 0 0 0 ($border-width-focus - $border-width) $theme-color; // Windows High Contrast mode will show this outline, but not the box-shadow. outline: 2px solid transparent; - outline-offset: -2px; } @@ -243,13 +151,13 @@ #{$selector} { /* Set left position when auto-fold is not on the body element. */ left: 0; - @include break-medium() { + @media (min-width: #{ ($break-medium + 1) }) { left: $admin-sidebar-width; } } .auto-fold #{$selector} { /* Auto fold is when on smaller breakpoints, nav menu auto collapses. */ - @include break-medium() { + @media (min-width: #{ ($break-medium + 1) }) { left: $admin-sidebar-width-collapsed; } @@ -262,13 +170,13 @@ .folded #{$selector} { left: 0; - @include break-medium() { + @media (min-width: #{ ($break-medium + 1) }) { left: $admin-sidebar-width-collapsed; } } /* Mobile menu opened. */ - @media (max-width: #{ ($break-medium) }) { + @media (max-width: #{ ($break-medium + 1) }) { .auto-fold .wp-responsive-open #{$selector} { left: $admin-sidebar-width-big; } @@ -416,7 +324,7 @@ } &:checked:focus { - box-shadow: 0 0 0 2px $medium-gray-text; + box-shadow: 0 0 0 $border-width-focus $medium-gray-text; } } @@ -459,7 +367,7 @@ } &:focus { - box-shadow: 0 0 0 2px $dark-gray-500; + box-shadow: 0 0 0 $border-width-focus $dark-gray-500; } } } diff --git a/packages/base-styles/_variables.scss b/packages/base-styles/_variables.scss index 5de37b965294c7..276bd120ab0b59 100644 --- a/packages/base-styles/_variables.scss +++ b/packages/base-styles/_variables.scss @@ -16,6 +16,8 @@ $editor-line-height: 1.8; $big-font-size: 18px; $mobile-text-min-font-size: 16px; // Any font size below 16px will cause Mobile Safari to "zoom in" $border-width: 1px; +$border-width-focus: 1.5px; +$border-width-tab: 4px; /** * Grid System. @@ -36,6 +38,7 @@ $grid-unit-60: 6 * $grid-unit; // 48px * Dimensions. */ +$icon-size: 24px; $button-size: 36px; $button-size-small: 24px; $panel-padding: 16px; @@ -49,6 +52,8 @@ $admin-sidebar-width-collapsed: 36px; $modal-min-width: 360px; $spinner-size: 18px; $mobile-header-toolbar-height: 44px; +$mobile-floating-toolbar-height: 44px; +$mobile-floating-toolbar-margin: 8px; /** @@ -75,25 +80,21 @@ $block-toolbar-height: $grid-unit-60; $mobile-block-toolbar-height: 44px; $block-padding: 14px; // Space between block footprint and focus boundaries. These are drawn outside the block footprint, and do not affect the size. $block-spacing: 4px; // Vertical space between blocks. -$block-side-ui-width: 28px; // Width of the movers/drag handle UI. +$block-side-ui-width: $button-size; // Width of the movers/drag handle UI. $block-side-ui-clearance: 2px; // Space between movers/drag handle UI, and block. $block-container-side-padding: $block-side-ui-width + $block-padding + 2 * $block-side-ui-clearance; // Total space left and right of the block footprint. $block-bg-padding--v: $block-padding + $block-spacing + $block-side-ui-clearance; // padding for Blocks with a background color (eg: paragraph or group) $block-bg-padding--h: $block-side-ui-width + $block-side-ui-clearance; // padding for Blocks with a background color (eg: paragraph or group) +$dimmed-opacity: 1; $block-edge-to-content: 16px; +$solid-border-space: 12px; +$dashed-border-space: 6px; $block-selected-margin: 3px; $block-selected-border-width: 1px; $block-selected-padding: 0; $block-selected-child-margin: 5px; -$block-selected-child-border-width: 1px; -$block-selected-child-padding: 0; $block-selected-to-content: $block-edge-to-content - $block-selected-margin - $block-selected-border-width; -$block-selected-child-to-content: $block-selected-to-content - $block-selected-child-margin - $block-selected-child-border-width; -$block-custom-appender-to-content: $block-selected-margin - $block-selected-border-width; -$block-media-container-to-content: $block-selected-child-margin + $block-selected-border-width; -$block-selected-vertical-margin-descendant: 2 * $block-selected-to-content; -$block-selected-vertical-margin-child: $block-edge-to-content; /** diff --git a/packages/base-styles/_z-index.scss b/packages/base-styles/_z-index.scss index 9a3f207b6be01f..b0b09d483dab9f 100644 --- a/packages/base-styles/_z-index.scss +++ b/packages/base-styles/_z-index.scss @@ -24,7 +24,7 @@ $z-layers: ( ".block-library-gallery-item__inline-menu": 20, ".block-editor-url-input__suggestions": 30, ".edit-post-layout__footer": 30, - ".block-editor-editor-skeleton__header": 30, + ".interface-interface-skeleton__header": 30, ".edit-site-header": 62, ".edit-widgets-header": 30, ".block-library-button__inline-link .block-editor-url-input__suggestions": 6, // URL suggestions for button block above sibling inserter @@ -62,7 +62,7 @@ $z-layers: ( // Show sidebar above wp-admin navigation bar for mobile viewports: // #wpadminbar { z-index: 99999 } - ".block-editor-editor-skeleton__sidebar": 100000, + ".interface-interface-skeleton__sidebar": 100000, ".edit-post-layout__toogle-sidebar-panel": 100000, ".edit-site-sidebar": 100000, ".edit-widgets-sidebar": 100000, @@ -73,7 +73,7 @@ $z-layers: ( // Show sidebar in greater than small viewports above editor related elements // but bellow #adminmenuback { z-index: 100 } - ".block-editor-editor-skeleton__sidebar {greater than small}": 90, + ".interface-interface-skeleton__sidebar {greater than small}": 90, ".edit-site-sidebar {greater than small}": 90, ".edit-widgets-sidebar {greater than small}": 90, @@ -102,12 +102,13 @@ $z-layers: ( ".components-popover.table-of-contents__popover": 99998, ".components-popover.block-editor-block-navigation__popover": 99998, ".components-popover.edit-post-more-menu__content": 99998, + ".components-popover.edit-site-more-menu__content": 99998, ".components-popover.block-editor-rich-text__inline-format-toolbar": 99998, ".components-autocomplete__results": 1000000, ".skip-to-selected-block": 100000, - ".block-editor-editor-skeleton__publish": 100000, + ".interface-interface-skeleton__actions": 100000, // Show NUX tips above popovers, wp-admin menus, submenus, and sidebar: ".nux-dot-tip": 1000001, diff --git a/packages/base-styles/package.json b/packages/base-styles/package.json index 6c678639d989a5..a5f8f21f0a621a 100644 --- a/packages/base-styles/package.json +++ b/packages/base-styles/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/base-styles", - "version": "1.4.0", + "version": "1.6.0", "description": "Base SCSS utilities and variables for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/blob/CHANGELOG.md b/packages/blob/CHANGELOG.md index 1288967c3cfdb6..6878f2dcfb709b 100644 --- a/packages/blob/CHANGELOG.md +++ b/packages/blob/CHANGELOG.md @@ -1,3 +1,11 @@ +## Master + +## 2.8.0 (2020-04-15) + +### New feature + +- Include TypeScript type declarations ([#18942](https://github.com/WordPress/gutenberg/pull/18942)) + ## 2.1.0 (2018-10-19) ### New Features diff --git a/packages/blob/package.json b/packages/blob/package.json index 86a19462a1e219..9789a8ecea13c5 100644 --- a/packages/blob/package.json +++ b/packages/blob/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/blob", - "version": "2.7.0", + "version": "2.8.0", "description": "Blob utilities for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -20,9 +20,10 @@ "main": "build/index.js", "module": "build-module/index.js", "react-native": "src/index", + "types": "build-types", "sideEffects": false, "dependencies": { - "@babel/runtime": "^7.8.3" + "@babel/runtime": "^7.9.2" }, "publishConfig": { "access": "public" diff --git a/packages/blob/src/index.js b/packages/blob/src/index.js index 61e90ef2b4c294..ef8ba7e2f7e394 100644 --- a/packages/blob/src/index.js +++ b/packages/blob/src/index.js @@ -4,7 +4,7 @@ const { createObjectURL, revokeObjectURL } = window.URL; /** - * @type {{[key: string]: File|undefined}} + * @type {Record} */ const cache = {}; diff --git a/packages/blob/tsconfig.json b/packages/blob/tsconfig.json new file mode 100644 index 00000000000000..3c2c31f506f132 --- /dev/null +++ b/packages/blob/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "src", + "declarationDir": "build-types" + }, + "include": [ "src/**/*" ] +} diff --git a/packages/block-directory/package.json b/packages/block-directory/package.json index 2e566e0e69288e..a9653a267c3f31 100644 --- a/packages/block-directory/package.json +++ b/packages/block-directory/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-directory", - "version": "1.5.5", + "version": "1.7.1", "description": "Extend editor with block directory features to search, download and install blocks.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/block-directory/src/components/block-ratings/index.js b/packages/block-directory/src/components/block-ratings/index.js index c55cace300028c..c04f6c0fd7c5cd 100644 --- a/packages/block-directory/src/components/block-ratings/index.js +++ b/packages/block-directory/src/components/block-ratings/index.js @@ -13,13 +13,11 @@ export const BlockRatings = ( { rating, ratingCount } ) => ( ({ ratingCount }) diff --git a/packages/block-directory/src/components/block-ratings/stars.js b/packages/block-directory/src/components/block-ratings/stars.js index 843fca4385ce2a..a2d13b0aacb51b 100644 --- a/packages/block-directory/src/components/block-ratings/stars.js +++ b/packages/block-directory/src/components/block-ratings/stars.js @@ -17,7 +17,13 @@ function Stars( { rating } ) { const emptyStarCount = 5 - ( fullStarCount + halfStarCount ); return ( -
+
{ times( fullStarCount, ( i ) => ( - { sprintf( __( 'Authored by %s' ), author ) } + { sprintf( + /* translators: %s: author name. */ + __( 'Authored by %s' ), + author + ) } { sprintf( + /* translators: 1: number of blocks. 2: average rating. */ _n( - 'This author has %d block, with an average rating of %d.', - 'This author has %d blocks, with an average rating of %d.', + 'This author has %1$d block, with an average rating of %2$d.', + 'This author has %1$d blocks, with an average rating of %2$d.', authorBlockCount ), authorBlockCount, diff --git a/packages/block-directory/src/components/downloadable-block-header/index.js b/packages/block-directory/src/components/downloadable-block-header/index.js index 78ab2962e60ce8..dc835ed3295399 100644 --- a/packages/block-directory/src/components/downloadable-block-header/index.js +++ b/packages/block-directory/src/components/downloadable-block-header/index.js @@ -20,10 +20,13 @@ function DownloadableBlockHeader( { return (
{ icon.match( /\.(jpeg|jpg|gif|png)(?:\?.*)?$/ ) !== null ? ( - // translators: %s: Name of the plugin e.g: "Akismet". { ) : ( diff --git a/packages/block-directory/src/components/downloadable-block-info/index.js b/packages/block-directory/src/components/downloadable-block-info/index.js index b6865a5c9197e9..4c65e639554a9d 100644 --- a/packages/block-directory/src/components/downloadable-block-info/index.js +++ b/packages/block-directory/src/components/downloadable-block-info/index.js @@ -19,6 +19,7 @@ function DownloadableBlockInfo( {
{ sprintf( + /* translators: %s: number of active installations. */ _n( '%d active installation', '%d active installations', diff --git a/packages/block-directory/src/components/downloadable-block-list-item/style.scss b/packages/block-directory/src/components/downloadable-block-list-item/style.scss index b32b58356c4fd4..84521724a1da0c 100644 --- a/packages/block-directory/src/components/downloadable-block-list-item/style.scss +++ b/packages/block-directory/src/components/downloadable-block-list-item/style.scss @@ -10,7 +10,7 @@ justify-content: center; background: transparent; word-break: break-word; - border-radius: $radius-round-rectangle; + border-radius: $radius-block-ui; border: $border-width solid $light-gray-500; transition: all 0.05s ease-in-out; @include reduce-motion("transition"); diff --git a/packages/block-directory/src/components/downloadable-blocks-panel/index.js b/packages/block-directory/src/components/downloadable-blocks-panel/index.js index 29d7cbb29ecac0..08d346d6774a58 100644 --- a/packages/block-directory/src/components/downloadable-blocks-panel/index.js +++ b/packages/block-directory/src/components/downloadable-blocks-panel/index.js @@ -55,6 +55,7 @@ function DownloadableBlocksPanel( { } const resultsFoundMessage = sprintf( + /* translators: %s: number of available blocks. */ _n( 'No blocks found in your library. We did find %d block available for download.', 'No blocks found in your library. We did find %d blocks available for download.', diff --git a/packages/block-editor/README.md b/packages/block-editor/README.md index 574e77a1ddce82..4c9673524d397e 100644 --- a/packages/block-editor/README.md +++ b/packages/block-editor/README.md @@ -93,6 +93,18 @@ _Returns_ - `WPElement`: Block Breadcrumb. +# **BlockContextProvider** + +Component which merges passed value with current consumed block context. + +_Related_ + +- + +_Parameters_ + +- _props_ `BlockContextProviderProps`: + # **BlockControls** Undocumented declaration. @@ -143,8 +155,9 @@ _Related_ _Parameters_ -- _blocks_ `(Array|Object)`: A block instance (object) or an array of blocks to be previewed. -- _viewportWidth_ `number`: Width of the preview container in pixels. Controls at what size the blocks will be rendered inside the preview. Default: 700. +- _preview_ `Object`: options for how the preview should be shown +- _preview.blocks_ `(Array|Object)`: A block instance (object) or an array of blocks to be previewed. +- _preview.viewportWidth_ `number`: Width of the preview container in pixels. Controls at what size the blocks will be rendered inside the preview. Default: 700. _Returns_ @@ -231,10 +244,6 @@ _Returns_ Undocumented declaration. -# **Editable** - -Renders an editable text input in which text formatting is not allowed. - # **FontSizePicker** Undocumented declaration. @@ -293,7 +302,7 @@ _Parameters_ _Returns_ -- `?string`: If fontSizeAttribute is set and an equal slug is found in fontSizes it returns the font size object for that slug. Otherwise, an object with just the size value based on customFontSize is returned. +- `?Object`: If fontSizeAttribute is set and an equal slug is found in fontSizes it returns the font size object for that slug. Otherwise, an object with just the size value based on customFontSize is returned. # **getFontSizeClass** @@ -307,6 +316,45 @@ _Returns_ - `string`: String with the class corresponding to the fontSize passed. The class is generated by appending 'has-' followed by fontSizeSlug in kebabCase and ending with '-font-size'. +# **getFontSizeObjectByValue** + +Returns the corresponding font size object for a given value. + +_Parameters_ + +- _fontSizes_ `Array`: Array of font size objects. +- _value_ `number`: Font size value. + +_Returns_ + +- `Object`: Font size object. + +# **getGradientSlugByValue** + +Retrieves the gradient slug per slug. + +_Parameters_ + +- _gradients_ `Array`: Gradient Palette +- _value_ `string`: Gradient value + +_Returns_ + +- `string`: Gradient slug. + +# **getGradientValueBySlug** + +Retrieves the gradient value per slug. + +_Parameters_ + +- _gradients_ `Array`: Gradient Palette +- _slug_ `string`: Gradient slug + +_Returns_ + +- `string`: Gradient value. + # **InnerBlocks** _Related_ diff --git a/packages/block-editor/package.json b/packages/block-editor/package.json index de1af791c8e084..d5b0385d3cb3fb 100644 --- a/packages/block-editor/package.json +++ b/packages/block-editor/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-editor", - "version": "3.7.5", + "version": "3.9.1", "description": "Generic block editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -22,7 +22,7 @@ "module": "build-module/index.js", "react-native": "src/index", "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/a11y": "file:../a11y", "@wordpress/blob": "file:../blob", "@wordpress/blocks": "file:../blocks", @@ -39,6 +39,7 @@ "@wordpress/is-shallow-equal": "file:../is-shallow-equal", "@wordpress/keyboard-shortcuts": "file:../keyboard-shortcuts", "@wordpress/keycodes": "file:../keycodes", + "@wordpress/priority-queue": "file:../priority-queue", "@wordpress/rich-text": "file:../rich-text", "@wordpress/token-list": "file:../token-list", "@wordpress/url": "file:../url", @@ -50,7 +51,7 @@ "dom-scroll-into-view": "^1.2.1", "inherits": "^2.0.3", "lodash": "^4.17.15", - "memize": "^1.0.5", + "memize": "^1.1.0", "react-autosize-textarea": "^3.0.2", "react-spring": "^8.0.19", "redux-multi": "^0.1.12", diff --git a/packages/editor/src/components/autocompleters/block.js b/packages/block-editor/src/autocompleters/block.js similarity index 91% rename from packages/editor/src/components/autocompleters/block.js rename to packages/block-editor/src/autocompleters/block.js index d4fb7507477d05..db17bd51b4d84c 100644 --- a/packages/editor/src/components/autocompleters/block.js +++ b/packages/block-editor/src/autocompleters/block.js @@ -6,9 +6,13 @@ import { once } from 'lodash'; /** * WordPress dependencies */ -import { select, dispatch } from '@wordpress/data'; +import { select } from '@wordpress/data'; import { createBlock } from '@wordpress/blocks'; -import { BlockIcon } from '@wordpress/block-editor'; + +/** + * Internal dependencies + */ +import BlockIcon from '../components/block-icon'; /** @typedef {import('@wordpress/block-editor').WPEditorInserterItem} WPEditorInserterItem */ @@ -68,7 +72,13 @@ function defaultGetSelectedBlockName() { * @return {Promise} Promise resolving once reusable blocks fetched. */ const fetchReusableBlocks = once( () => { - dispatch( 'core/editor' ).__experimentalFetchReusableBlocks(); + const { __experimentalFetchReusableBlocks } = select( + 'core/block-editor' + ).getSettings(); + + if ( __experimentalFetchReusableBlocks ) { + __experimentalFetchReusableBlocks(); + } } ); /** @@ -84,7 +94,7 @@ export function createBlockCompleter( { } = {} ) { return { name: 'blocks', - className: 'editor-autocompleters__block', + className: 'block-editor-autocompleters__block', triggerPrefix: '/', options() { fetchReusableBlocks(); diff --git a/packages/block-editor/src/autocompleters/style.scss b/packages/block-editor/src/autocompleters/style.scss new file mode 100644 index 00000000000000..fc51b518435e50 --- /dev/null +++ b/packages/block-editor/src/autocompleters/style.scss @@ -0,0 +1,5 @@ +.block-editor-autocompleters__block { + .block-editor-block-icon { + margin-right: 8px; + } +} diff --git a/packages/editor/src/components/autocompleters/test/block.js b/packages/block-editor/src/autocompleters/test/block.js similarity index 99% rename from packages/editor/src/components/autocompleters/test/block.js rename to packages/block-editor/src/autocompleters/test/block.js index 87534d69d159d2..91a7c164cf396e 100644 --- a/packages/editor/src/components/autocompleters/test/block.js +++ b/packages/block-editor/src/autocompleters/test/block.js @@ -7,7 +7,7 @@ import { shallow } from 'enzyme'; * Internal dependencies */ import blockCompleter, { createBlockCompleter } from '../block'; -import '../../../'; +import '../../store'; describe( 'block', () => { let originalFetch; diff --git a/packages/block-editor/src/components/alignment-toolbar/index.js b/packages/block-editor/src/components/alignment-toolbar/index.js index 4e44ea01387b4e..2536e2e7e79b96 100644 --- a/packages/block-editor/src/components/alignment-toolbar/index.js +++ b/packages/block-editor/src/components/alignment-toolbar/index.js @@ -30,6 +30,7 @@ const DEFAULT_ALIGNMENT_CONTROLS = [ const POPOVER_PROPS = { position: 'bottom right', + isAlternate: true, }; export function AlignmentToolbar( props ) { diff --git a/packages/block-editor/src/components/alignment-toolbar/test/__snapshots__/index.js.snap b/packages/block-editor/src/components/alignment-toolbar/test/__snapshots__/index.js.snap index fad7ec9756a73a..4c5300651aef32 100644 --- a/packages/block-editor/src/components/alignment-toolbar/test/__snapshots__/index.js.snap +++ b/packages/block-editor/src/components/alignment-toolbar/test/__snapshots__/index.js.snap @@ -50,6 +50,7 @@ exports[`AlignmentToolbar should allow custom alignment controls to be specified label="Change text alignment" popoverProps={ Object { + "isAlternate": true, "position": "bottom right", } } @@ -121,6 +122,7 @@ exports[`AlignmentToolbar should match snapshot 1`] = ` label="Change text alignment" popoverProps={ Object { + "isAlternate": true, "position": "bottom right", } } diff --git a/packages/block-editor/src/components/autocomplete/index.js b/packages/block-editor/src/components/autocomplete/index.js index 2deea118054500..acba4f26729233 100644 --- a/packages/block-editor/src/components/autocomplete/index.js +++ b/packages/block-editor/src/components/autocomplete/index.js @@ -9,11 +9,22 @@ import { clone } from 'lodash'; import { applyFilters, hasFilter } from '@wordpress/hooks'; import { compose } from '@wordpress/compose'; import { Autocomplete as OriginalAutocomplete } from '@wordpress/components'; +import { useMemo } from '@wordpress/element'; +import { getDefaultBlockName } from '@wordpress/blocks'; /** * Internal dependencies */ import { withBlockEditContext } from '../block-edit/context'; +import blockAutocompleter from '../../autocompleters/block'; + +/** + * Shared reference to an empty array for cases where it is important to avoid + * returning a new array reference on every invocation. + * + * @type {Array} + */ +const EMPTY_ARRAY = []; /** * Wrap the default Autocomplete component with one that @@ -26,7 +37,13 @@ import { withBlockEditContext } from '../block-edit/context'; */ export function withFilteredAutocompleters( Autocomplete ) { return ( props ) => { - let { completers = [] } = props; + let { completers = EMPTY_ARRAY, blockName } = props; + completers = useMemo( () => { + if ( blockName === getDefaultBlockName() ) { + return completers.concat( [ blockAutocompleter ] ); + } + return completers; + }, [ completers, blockName ] ); if ( hasFilter( 'editor.Autocomplete.completers' ) ) { completers = applyFilters( diff --git a/packages/block-editor/src/components/block-breadcrumb/style.scss b/packages/block-editor/src/components/block-breadcrumb/style.scss index db915e4d68f7bc..6dc47828019ad9 100644 --- a/packages/block-editor/src/components/block-breadcrumb/style.scss +++ b/packages/block-editor/src/components/block-breadcrumb/style.scss @@ -17,6 +17,7 @@ height: $button-size-small; line-height: $button-size-small; padding: 0; + position: relative; &:hover:not(:disabled) { text-decoration: underline; @@ -24,10 +25,20 @@ } &:focus { - @include square-style__focus(); - outline-offset: -2px; box-shadow: none; } + + &:focus::before { + content: ""; + display: block; + position: absolute; + border-radius: $radius-block-ui; + top: $border-width; + right: $border-width; + bottom: $border-width; + left: $border-width; + box-shadow: inset 0 0 0 $border-width-focus $theme-color; + } } .block-editor-block-breadcrumb__current { diff --git a/packages/block-editor/src/components/block-card/index.js b/packages/block-editor/src/components/block-card/index.js index 674d437d9c7a3e..aaff1af27e16dd 100644 --- a/packages/block-editor/src/components/block-card/index.js +++ b/packages/block-editor/src/components/block-card/index.js @@ -8,12 +8,12 @@ function BlockCard( { blockType } ) {
-
+

{ blockType.title } -

-
+ + { blockType.description } -
+
); diff --git a/packages/block-editor/src/components/block-card/style.scss b/packages/block-editor/src/components/block-card/style.scss index 3b1c753929f868..993ac878d03c4c 100644 --- a/packages/block-editor/src/components/block-card/style.scss +++ b/packages/block-editor/src/components/block-card/style.scss @@ -18,7 +18,9 @@ .block-editor-block-card__title { font-weight: 500; - margin-bottom: 5px; + &.block-editor-block-card__title { + margin: 0 0 5px; + } } .block-editor-block-card__description { diff --git a/packages/block-editor/src/components/block-context/README.md b/packages/block-editor/src/components/block-context/README.md new file mode 100644 index 00000000000000..acb51b48e14576 --- /dev/null +++ b/packages/block-editor/src/components/block-context/README.md @@ -0,0 +1,57 @@ +Block Context +============= + +Block Context is a React implementation of WordPress's block context. Block context, much like [React's context](https://reactjs.org/docs/context.html), is a method for passing and inheriting values deeply through a hierarchy of blocks. Because of the similarities with React's context, the client-side implementation here is quite minimal. It is complemented by equivalent behaviors in the server-side rendering of a block. + +Note that the implementation of Block Context is distinct from [the `BlockEdit` context](../block-edit). While it is true that both provide context relevant for the editing of a block, Block Context is implemented separately so as to prioritize it as most identifiable amongst the machinery of block context, and not amongst other client-side editing context of a block. + +## Usage + +Currently, only the [Provider component](https://reactjs.org/docs/context.html#contextprovider) is made available on the public interface of the `@wordpress/block-editor` module. This can be used to add or override context which can then be consumed by blocks rendered within that context in the block editor. + +```js +import { BlockContextProvider } from '@wordpress/block-editor'; + +function MyCustomPostEditor() { + return ( + + + + ); +} +``` + +Internal to the `@wordpress/block-editor` module, a component can access the [full Context object](https://reactjs.org/docs/context.html#api), typically for use in combination with [`useContext`](https://reactjs.org/docs/hooks-reference.html#usecontext). + +```js +import { useContext } from '@wordpress/element'; + +// Only available internally within `@wordpress/block-editor`! +import BlockContext from '../block-context'; + +function MyBlockComponent() { + const { postId } = useContext( BlockContext ); + + return 'The current post ID is: ' + postId; +} +``` + +The reason `BlockContext` is only internally available within the `@wordpress/block-editor` module is to reinforce the expectation that external consumption of values from block context should be declared on the block registration using the `context` property. + +## Props + +`BlockContextProvider` behaves like a standard [`Context.Provider` component](https://reactjs.org/docs/context.html#contextprovider). It receives `value` and `children` props. The `value` is merged with the current block context value. + +### `value` + +- Type: `Record` +- Required: Yes + +Context value to merge with current value. + +### `children` + +- Type: `ReactNode` +- Required: Yes + +Component children. diff --git a/packages/block-editor/src/components/block-context/index.js b/packages/block-editor/src/components/block-context/index.js new file mode 100644 index 00000000000000..617ae2ef2a8ed5 --- /dev/null +++ b/packages/block-editor/src/components/block-context/index.js @@ -0,0 +1,36 @@ +/** + * WordPress dependencies + */ +import { createContext, useContext, useMemo } from '@wordpress/element'; + +/** @typedef {import('react').ReactNode} ReactNode */ + +/** + * @typedef BlockContextProviderProps + * + * @property {Record} value Context value to merge with current + * value. + * @property {ReactNode} children Component children. + */ + +/** @type {import('react').Context>} */ +const Context = createContext( {} ); + +/** + * Component which merges passed value with current consumed block context. + * + * @see https://github.com/WordPress/gutenberg/blob/master/packages/block-editor/src/components/block-context/README.md + * + * @param {BlockContextProviderProps} props + */ +export function BlockContextProvider( { value, children } ) { + const context = useContext( Context ); + const nextValue = useMemo( () => ( { ...context, ...value } ), [ + context, + value, + ] ); + + return ; +} + +export default Context; diff --git a/packages/block-editor/src/components/block-edit/edit.js b/packages/block-editor/src/components/block-edit/edit.js index a4f08d0c96a36f..936fb24c4fc2a1 100644 --- a/packages/block-editor/src/components/block-edit/edit.js +++ b/packages/block-editor/src/components/block-edit/edit.js @@ -2,6 +2,7 @@ * External dependencies */ import classnames from 'classnames'; +import { pick } from 'lodash'; /** * WordPress dependencies @@ -12,10 +13,36 @@ import { hasBlockSupport, getBlockType, } from '@wordpress/blocks'; +import { useContext, useMemo } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import BlockContext from '../block-context'; + +/** + * Default value used for blocks which do not define their own context needs, + * used to guarantee that a block's `context` prop will always be an object. It + * is assigned as a constant since it is always expected to be an empty object, + * and in order to avoid unnecessary React reconciliations of a changing object. + * + * @type {{}} + */ +const DEFAULT_BLOCK_CONTEXT = {}; export const Edit = ( props ) => { const { attributes = {}, name } = props; const blockType = getBlockType( name ); + const blockContext = useContext( BlockContext ); + + // Assign context values using the block type's declared context needs. + const context = useMemo( + () => + blockType && blockType.context + ? pick( blockContext, blockType.context ) + : DEFAULT_BLOCK_CONTEXT, + [ blockType, blockContext ] + ); if ( ! blockType ) { return null; @@ -32,7 +59,7 @@ export const Edit = ( props ) => { ); if ( lightBlockWrapper ) { - return ; + return ; } // Generate a class name for the block's editable form @@ -41,7 +68,9 @@ export const Edit = ( props ) => { : null; const className = classnames( generatedClassName, attributes.className ); - return ; + return ( + + ); }; export default withFilters( 'editor.BlockEdit' )( Edit ); diff --git a/packages/block-editor/src/components/block-edit/test/edit.js b/packages/block-editor/src/components/block-edit/test/edit.js index 0b07eb03b2aad6..6c273de2351961 100644 --- a/packages/block-editor/src/components/block-edit/test/edit.js +++ b/packages/block-editor/src/components/block-edit/test/edit.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { shallow } from 'enzyme'; +import { shallow, mount } from 'enzyme'; import { noop } from 'lodash'; /** @@ -17,6 +17,7 @@ import { * Internal dependencies */ import { Edit } from '../edit'; +import { BlockContextProvider } from '../../block-context'; describe( 'Edit', () => { afterEach( () => { @@ -79,4 +80,47 @@ describe( 'Edit', () => { ); expect( wrapper.find( edit ).hasClass( 'my-class' ) ).toBe( true ); } ); + + it( 'should assign context', () => { + const edit = ( { context } ) => context.value; + registerBlockType( 'core/test-block', { + category: 'common', + title: 'block title', + context: [ 'value' ], + edit, + save: noop, + } ); + + const wrapper = mount( + + + + ); + + expect( wrapper.html() ).toBe( 'Ok' ); + } ); + + describe( 'light wrapper', () => { + it( 'should assign context', () => { + const edit = ( { context } ) => context.value; + registerBlockType( 'core/test-block', { + category: 'common', + title: 'block title', + context: [ 'value' ], + supports: { + lightBlockWrapper: true, + }, + edit, + save: noop, + } ); + + const wrapper = mount( + + + + ); + + expect( wrapper.html() ).toBe( 'Ok' ); + } ); + } ); } ); diff --git a/packages/block-editor/src/components/block-inspector/index.js b/packages/block-editor/src/components/block-inspector/index.js index e1b4d017e03d67..0a0eab0784ab19 100644 --- a/packages/block-editor/src/components/block-inspector/index.js +++ b/packages/block-editor/src/components/block-inspector/index.js @@ -32,7 +32,6 @@ const BlockInspector = ( { showNoBlockSelectedMessage = true, } ) => { const slot = useSlot( InspectorAdvancedControls.slotName ); - const hasFills = Boolean( slot.fills && slot.fills.length ); if ( count > 1 ) { return ; @@ -60,6 +59,8 @@ const BlockInspector = ( { return null; } + const hasFills = Boolean( slot.fills && slot.fills.length ); + return (
diff --git a/packages/block-editor/src/components/block-list/block-elements.js b/packages/block-editor/src/components/block-list/block-elements.js new file mode 100644 index 00000000000000..1d71649a1cc479 --- /dev/null +++ b/packages/block-editor/src/components/block-list/block-elements.js @@ -0,0 +1,23 @@ +const ELEMENTS = [ + 'p', + 'div', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + 'ol', + 'ul', + 'li', + 'figure', + 'nav', + 'pre', + 'header', + 'section', + 'aside', + 'footer', + 'main', +]; + +export default ELEMENTS; diff --git a/packages/block-editor/src/components/block-list/block-mobile-floating-toolbar.native.js b/packages/block-editor/src/components/block-list/block-mobile-floating-toolbar.native.js deleted file mode 100644 index fc8876253734c2..00000000000000 --- a/packages/block-editor/src/components/block-list/block-mobile-floating-toolbar.native.js +++ /dev/null @@ -1,19 +0,0 @@ -/** - * External dependencies - */ -import { View, TouchableWithoutFeedback } from 'react-native'; - -/** - * Internal dependencies - */ -import styles from './block-mobile-floating-toolbar.scss'; - -const FloatingToolbar = ( { children } ) => { - return ( - - { children } - - ); -}; - -export default FloatingToolbar; diff --git a/packages/block-editor/src/components/block-list/block-mobile-floating-toolbar.native.scss b/packages/block-editor/src/components/block-list/block-mobile-floating-toolbar.native.scss deleted file mode 100644 index 5b12591ec44361..00000000000000 --- a/packages/block-editor/src/components/block-list/block-mobile-floating-toolbar.native.scss +++ /dev/null @@ -1,24 +0,0 @@ -$floating-toolbar-height: 44; - -.floatingToolbar { - background-color: $dark-gray-500; - margin: auto; - min-width: 100; - max-height: $floating-toolbar-height; - border-radius: 22px; - flex-direction: row; - z-index: 100; - height: $floating-toolbar-height; - align-items: center; - justify-content: center; - align-self: center; - margin-bottom: 8px; -} - -.floatingToolbarFillColor { - background-color: rgba(#1d2327, 0.85); -} - -.floatingToolbarFillColorDark { - background-color: rgba(#3c434a, 0.85); -} diff --git a/packages/block-editor/src/components/block-list/block-wrapper.js b/packages/block-editor/src/components/block-list/block-wrapper.js index c728b2a8a01364..52f353428e23f0 100644 --- a/packages/block-editor/src/components/block-list/block-wrapper.js +++ b/packages/block-editor/src/components/block-list/block-wrapper.js @@ -27,6 +27,7 @@ import { isInsideRootBlock } from '../../utils/dom'; import useMovingAnimation from './moving-animation'; import { Context, BlockNodes } from './root-container'; import { BlockContext } from './block'; +import ELEMENTS from './block-elements'; const BlockComponent = forwardRef( ( { children, tagName = 'div', __unstableIsHtml, ...props }, wrapper ) => { @@ -101,7 +102,10 @@ const BlockComponent = forwardRef( // should only consider tabbables within editable display, since it // may be the wrapper itself or a side control which triggered the // focus event, don't unnecessary transition to an inner tabbable. - if ( wrapper.current.contains( document.activeElement ) ) { + if ( + document.activeElement && + isInsideRootBlock( wrapper.current, document.activeElement ) + ) { return; } @@ -109,9 +113,11 @@ const BlockComponent = forwardRef( const textInputs = focus.tabbable .find( wrapper.current ) .filter( isTextField ) - // Exclude inner blocks - .filter( ( node ) => - isInsideRootBlock( wrapper.current, node ) + // Exclude inner blocks and block appenders + .filter( + ( node ) => + isInsideRootBlock( wrapper.current, node ) && + ! node.closest( '.block-list-appender' ) ); // If reversed (e.g. merge via backspace), use the last in the set of @@ -199,7 +205,11 @@ const BlockComponent = forwardRef( { ...props } id={ blockElementId } ref={ wrapper } - className={ classnames( className, props.className ) } + className={ classnames( + className, + props.className, + wrapperProps && wrapperProps.className + ) } data-block={ clientId } data-type={ name } data-title={ blockTitle } @@ -209,6 +219,7 @@ const BlockComponent = forwardRef( onMouseLeave={ isSelected ? onMouseLeave : undefined } tabIndex="0" style={ { + ...( wrapperProps ? wrapperProps.style : {} ), ...( props.style || {} ), ...animationStyle, } } @@ -219,23 +230,7 @@ const BlockComponent = forwardRef( } ); -const elements = [ - 'p', - 'div', - 'h1', - 'h2', - 'h3', - 'h4', - 'h5', - 'h6', - 'ol', - 'ul', - 'li', - 'figure', - 'nav', -]; - -const ExtendedBlockComponent = elements.reduce( ( acc, element ) => { +const ExtendedBlockComponent = ELEMENTS.reduce( ( acc, element ) => { acc[ element ] = forwardRef( ( props, ref ) => { return ; } ); diff --git a/packages/block-editor/src/components/block-list/block-wrapper.native.js b/packages/block-editor/src/components/block-list/block-wrapper.native.js index 69cbf52723125a..c97dae59059f54 100644 --- a/packages/block-editor/src/components/block-list/block-wrapper.native.js +++ b/packages/block-editor/src/components/block-list/block-wrapper.native.js @@ -1,20 +1,9 @@ -const elements = [ - 'p', - 'div', - 'h1', - 'h2', - 'h3', - 'h4', - 'h5', - 'h6', - 'ol', - 'ul', - 'li', - 'figure', - 'nav', -]; +/** + * Internal dependencies + */ +import ELEMENTS from './block-elements'; -const ExtendedBlockComponent = elements.reduce( ( acc, element ) => { +const ExtendedBlockComponent = ELEMENTS.reduce( ( acc, element ) => { acc[ element ] = element; return acc; }, String ); diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index 52b1a915364b04..448f4b74514565 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -39,6 +39,7 @@ function BlockListBlock( { isLocked, clientId, rootClientId, + isHighlighted, isSelected, isMultiSelected, isPartOfMultiSelection, @@ -61,7 +62,6 @@ function BlockListBlock( { enableAnimation, isNavigationMode, isMultiSelecting, - hasSelectedUI = true, } ) { // In addition to withSelect, we should favor using useSelect in this // component going forward to avoid leaking new props to the public API @@ -87,7 +87,7 @@ function BlockListBlock( { isDraggingBlocks && ( isSelected || isPartOfMultiSelection ); // Determine whether the block has props to apply to the wrapper. - if ( ! lightBlockWrapper && blockType.getEditWrapperProps ) { + if ( blockType.getEditWrapperProps ) { wrapperProps = { ...wrapperProps, ...blockType.getEditWrapperProps( attributes ), @@ -109,9 +109,9 @@ function BlockListBlock( { customClassName, 'wp-block block-editor-block-list__block', { - 'has-selected-ui': hasSelectedUI, 'has-warning': ! isValid || !! hasError || isUnregisteredBlock, 'is-selected': isSelected, + 'is-highlighted': isHighlighted, 'is-multi-selected': isMultiSelected, 'is-reusable': isReusableBlock( blockType ), 'is-dragging': isDragging, @@ -228,6 +228,7 @@ const applyWithSelect = withSelect( getTemplateLock, __unstableGetBlockWithoutInnerBlocks, isNavigationMode, + isBlockHighlighted, } = select( 'core/block-editor' ); const block = __unstableGetBlockWithoutInnerBlocks( clientId ); const isSelected = isBlockSelected( clientId ); @@ -248,6 +249,7 @@ const applyWithSelect = withSelect( const { name, attributes, isValid } = block || {}; return { + isHighlighted: isBlockHighlighted( clientId ), isMultiSelected: isBlockMultiSelected( clientId ), isPartOfMultiSelection: isBlockMultiSelected( clientId ) || diff --git a/packages/block-editor/src/components/block-list/block.native.js b/packages/block-editor/src/components/block-list/block.native.js index 2501094b59339c..773c6d19fb9913 100644 --- a/packages/block-editor/src/components/block-list/block.native.js +++ b/packages/block-editor/src/components/block-list/block.native.js @@ -7,15 +7,12 @@ import { View, Text, TouchableWithoutFeedback } from 'react-native'; * WordPress dependencies */ import { Component } from '@wordpress/element'; -import { ToolbarButton, Toolbar } from '@wordpress/components'; import { withDispatch, withSelect } from '@wordpress/data'; import { compose, withPreferredColorScheme } from '@wordpress/compose'; import { getBlockType, - getUnregisteredTypeHandlerName, __experimentalGetAccessibleBlockLabel as getAccessibleBlockLabel, } from '@wordpress/blocks'; -import { __ } from '@wordpress/i18n'; /** * Internal dependencies @@ -24,9 +21,6 @@ import styles from './block.scss'; import BlockEdit from '../block-edit'; import BlockInvalidWarning from './block-invalid-warning'; import BlockMobileToolbar from '../block-mobile-toolbar'; -import FloatingToolbar from './block-mobile-floating-toolbar'; -import Breadcrumbs from './breadcrumb'; -import NavigateUpSVG from './nav-up-icon'; class BlockListBlock extends Component { constructor() { @@ -67,6 +61,9 @@ class BlockListBlock extends Component { this.props.onCaretVerticalPositionChange } clientId={ this.props.clientId } + parentWidth={ this.props.parentWidth } + contentStyle={ this.props.contentStyle } + onDeleteBlock={ this.props.onDeleteBlock } /> ); } @@ -79,104 +76,6 @@ class BlockListBlock extends Component { ); } - applySelectedBlockStyle() { - const { hasChildren, getStylesFromColorScheme } = this.props; - - const fullSolidBorderStyle = { - // define style for full border - ...styles.fullSolidBordered, - ...getStylesFromColorScheme( - styles.solidBorderColor, - styles.solidBorderColorDark - ), - }; - - if ( hasChildren ) { - // if block has children apply style for selected parent - return { ...styles.selectedParent, ...fullSolidBorderStyle }; - } - - /* selected block is one of below: - 1. does not have children - 2. is not on root list level - 3. is an emty group block on root or nested level */ - return { ...styles.selectedLeaf, ...fullSolidBorderStyle }; - } - - applyUnSelectedBlockStyle() { - const { - hasChildren, - isParentSelected, - isAncestorSelected, - hasParent, - getStylesFromColorScheme, - isLastBlock, - } = this.props; - - // if block does not have parent apply neutral or full - // margins depending if block has children or not - if ( ! hasParent ) { - return hasChildren ? styles.neutral : styles.full; - } - - if ( isParentSelected ) { - // parent of a block is selected - const dashedBorderStyle = { - // define style for dashed border - ...styles.dashedBordered, - ...getStylesFromColorScheme( - styles.dashedBorderColor, - styles.dashedBorderColorDark - ), - }; - - // return apply childOfSelected or childOfSelectedLeaf - // margins depending if block has children or not - return { - ...( hasChildren - ? styles.childOfSelected - : styles.childOfSelectedLeaf ), - ...dashedBorderStyle, - ...( ! isLastBlock && styles.marginVerticalChild ), - }; - } - - if ( isAncestorSelected ) { - // ancestor of a block is selected - return { - ...styles.descendantOfSelectedLeaf, - ...( hasChildren && { - ...styles.marginHorizontalNone, - ...styles.marginVerticalNone, - } ), - ...( ! isLastBlock && styles.marginVerticalDescendant ), - }; - } - - // if none of above condition are met return apply neutral or full - // margins depending if block has children or not - return hasChildren ? styles.neutral : styles.full; - } - - applyBlockStyle() { - const { isSelected, isDimmed } = this.props; - - return [ - isSelected - ? this.applySelectedBlockStyle() - : this.applyUnSelectedBlockStyle(), - isDimmed && styles.dimmed, - ]; - } - - applyToolbarStyle() { - const { hasChildren, isUnregisteredBlock } = this.props; - - if ( ! hasChildren || isUnregisteredBlock ) { - return styles.neutralToolbar; - } - } - render() { const { attributes, @@ -187,11 +86,15 @@ class BlockListBlock extends Component { isValid, order, title, - parentId, + isDimmed, isTouchable, - hasParent, - onSelect, - showFloatingToolbar, + onDeleteBlock, + isStackedHorizontally, + isParentSelected, + getStylesFromColorScheme, + marginVertical, + marginHorizontal, + isInnerBlockSelected, } = this.props; const accessibilityLabel = getAccessibleBlockLabel( @@ -200,33 +103,48 @@ class BlockListBlock extends Component { order + 1 ); + const accessible = ! ( isSelected || isInnerBlockSelected ); + return ( - - { showFloatingToolbar && ( - - { hasParent && ( - - onSelect( parentId ) } - icon={ NavigateUpSVG } - /> - - - ) } - - - ) } + + { isSelected && ( + + ) } + { isParentSelected && ( + + ) } { isValid ? ( this.getBlockForType() ) : ( @@ -235,9 +153,15 @@ class BlockListBlock extends Component { icon={ icon } /> ) } - + { isSelected && ( - + ) } @@ -255,20 +179,18 @@ export default compose( [ __unstableGetBlockWithoutInnerBlocks, getBlockHierarchyRootClientId, getSelectedBlockClientId, - getBlock, getBlockRootClientId, getLowestCommonAncestorWithSelectedBlock, getBlockParents, - getBlockCount, + hasSelectedInnerBlock, } = select( 'core/block-editor' ); const order = getBlockIndex( clientId, rootClientId ); const isSelected = isBlockSelected( clientId ); - const isLastBlock = order === getBlockCount( rootClientId ) - 1; + const isInnerBlockSelected = hasSelectedInnerBlock( clientId ); const block = __unstableGetBlockWithoutInnerBlocks( clientId ); const { name, attributes, isValid } = block || {}; - const isUnregisteredBlock = name === getUnregisteredTypeHandlerName(); const blockType = getBlockType( name || 'core/missing' ); const title = blockType.title; const icon = blockType.icon; @@ -277,10 +199,6 @@ export default compose( [ const parentId = parents[ 0 ] || ''; const rootBlockId = getBlockHierarchyRootClientId( clientId ); - const rootBlock = getBlock( rootBlockId ); - const hasRootInnerBlocks = rootBlock.innerBlocks.length !== 0; - - const showFloatingToolbar = isSelected && hasRootInnerBlocks; const selectedBlockClientId = getSelectedBlockClientId(); @@ -292,9 +210,6 @@ export default compose( [ ? parents[ commonAncestorIndex ] : parents[ parents.length - 1 ]; - const hasChildren = - ! isUnregisteredBlock && !! getBlockCount( clientId ); - const hasParent = !! parentId; const isParentSelected = selectedBlockClientId && selectedBlockClientId === parentId; const isAncestorSelected = @@ -329,19 +244,14 @@ export default compose( [ title, attributes, blockType, - isLastBlock, isSelected, + isInnerBlockSelected, isValid, - parentId, isParentSelected, firstToSelectId, - hasChildren, - hasParent, isAncestorSelected, isTouchable, isDimmed, - isUnregisteredBlock, - showFloatingToolbar, }; } ), withDispatch( ( dispatch, ownProps, { select } ) => { diff --git a/packages/block-editor/src/components/block-list/block.native.scss b/packages/block-editor/src/components/block-list/block.native.scss index 4c6936e57f5458..aa3d6d1248f595 100644 --- a/packages/block-editor/src/components/block-list/block.native.scss +++ b/packages/block-editor/src/components/block-list/block.native.scss @@ -2,18 +2,6 @@ flex: 1 1 auto; } -.fullSolidBordered { - border-width: $block-selected-border-width; - border-radius: 4px; - border-style: solid; -} - -.dashedBordered { - border-width: $block-selected-child-border-width; - border-radius: 2px; - border-style: dashed; -} - .solidBorderColor { border-color: $blue-wordpress; } @@ -31,32 +19,7 @@ } .dimmed { - opacity: 0.2; -} - -.horizontalSpaceNone { - padding-left: 0; - padding-right: 0; - margin-left: 0; - margin-right: 0; -} - -.marginHorizontalNone { - margin-left: 0; - margin-right: 0; -} - -.marginVerticalDescendant { - margin-bottom: $block-selected-vertical-margin-descendant; -} - -.marginVerticalChild { - margin-bottom: $block-selected-vertical-margin-child; -} - -.marginVerticalNone { - margin-top: 0; - margin-bottom: 0; + opacity: $dimmed-opacity; } .blockTitle { @@ -66,44 +29,6 @@ padding-bottom: 4px; } -.neutral { - margin: 0; - border: 0; - padding: 0; -} - -.full { - margin: $block-edge-to-content; - border: 0; - padding: 0; -} - -.selectedLeaf { - margin: $block-selected-margin; - padding-left: $block-selected-to-content; - padding-right: $block-selected-to-content; - padding-top: $block-selected-to-content; -} - -.selectedParent { - margin: $block-selected-margin; - padding: 0; -} - -.childOfSelected { - margin: $block-selected-child-margin; - padding: 0; -} - -.childOfSelectedLeaf { - margin: $block-selected-child-margin; - padding: $block-selected-child-to-content; -} - -.descendantOfSelectedLeaf { - margin: $block-selected-child-to-content; -} - .aztec_container { flex: 1; } @@ -116,24 +41,29 @@ min-height: 50px; } -.toolbar { - border-left-width: 0; - margin-right: auto; - padding-left: 2px; - height: 44px; +.neutralToolbar { + margin-left: -$block-edge-to-content; + margin-right: -$block-edge-to-content; } -.pipe { - margin-top: auto; - margin-bottom: auto; - margin-left: 2px; - height: 28px; - width: 1px; - background-color: #e9eff3; - opacity: 0.4; +.solidBorder { + position: absolute; + top: -$solid-border-space; + bottom: 0; + left: -$solid-border-space; + right: -$solid-border-space; + border-width: $block-selected-border-width; + border-radius: 4px; + border-style: solid; } -.neutralToolbar { - margin-left: -$block-edge-to-content; - margin-right: -$block-edge-to-content; +.dashedBorder { + position: absolute; + top: -$dashed-border-space; + bottom: -$dashed-border-space; + left: -$dashed-border-space; + right: -$dashed-border-space; + border-width: $block-selected-border-width; + border-radius: 2px; + border-style: dashed; } diff --git a/packages/block-editor/src/components/block-list/breadcrumb.js b/packages/block-editor/src/components/block-list/breadcrumb.js index a47db75152663e..2151725040c461 100644 --- a/packages/block-editor/src/components/block-list/breadcrumb.js +++ b/packages/block-editor/src/components/block-list/breadcrumb.js @@ -1,7 +1,7 @@ /** * WordPress dependencies */ -import { Toolbar, Button } from '@wordpress/components'; +import { Button } from '@wordpress/components'; import { useSelect, useDispatch } from '@wordpress/data'; import { useEffect, useRef } from '@wordpress/element'; import { BACKSPACE, DELETE } from '@wordpress/keycodes'; @@ -75,16 +75,14 @@ function BlockBreadcrumb( { return (
- - - +
); } diff --git a/packages/block-editor/src/components/block-list/breadcrumb.native.js b/packages/block-editor/src/components/block-list/breadcrumb.native.js index 0084d8485a326b..027b93abf6b7d3 100644 --- a/packages/block-editor/src/components/block-list/breadcrumb.native.js +++ b/packages/block-editor/src/components/block-list/breadcrumb.native.js @@ -9,7 +9,7 @@ import { getBlockType } from '@wordpress/blocks'; /** * External dependencies */ -import { View, Text, TouchableOpacity } from 'react-native'; +import { View, Text, TouchableOpacity, I18nManager } from 'react-native'; /** * Internal dependencies @@ -50,7 +50,10 @@ const BlockBreadcrumb = ( { fill={ styles.icon.color } />, - + , ] } { blockClientIds.map( ( clientId, index ) => { const isBlockInSelection = hasMultiSelection @@ -108,9 +103,6 @@ function BlockList( // otherwise there might be a small delay to trigger the animation. index={ index } enableAnimation={ enableAnimation } - hasSelectedUI={ - __experimentalUIParts.hasSelectedUI - } className={ clientId === targetClientId ? 'is-drop-target' diff --git a/packages/block-editor/src/components/block-list/index.native.js b/packages/block-editor/src/components/block-list/index.native.js index b43b6f82c94e0a..cedd71aee36156 100644 --- a/packages/block-editor/src/components/block-list/index.native.js +++ b/packages/block-editor/src/components/block-list/index.native.js @@ -7,7 +7,7 @@ import { View, Platform, TouchableWithoutFeedback } from 'react-native'; /** * WordPress dependencies */ -import { Component } from '@wordpress/element'; +import { Component, createContext } from '@wordpress/element'; import { withDispatch, withSelect } from '@wordpress/data'; import { compose, withPreferredColorScheme } from '@wordpress/compose'; import { createBlock } from '@wordpress/blocks'; @@ -25,6 +25,8 @@ import BlockListBlock from './block'; import BlockListAppender from '../block-list-appender'; import BlockInsertionPoint from './insertion-point'; +const BlockListContext = createContext(); + export class BlockList extends Component { constructor() { super( ...arguments ); @@ -72,42 +74,82 @@ export class BlockList extends Component { const { shouldShowInsertionPointBefore } = this.props; const willShowInsertionPoint = shouldShowInsertionPointBefore(); // call without the client_id argument since this is the appender return ( - - - + + + + + ); } shouldShowInnerBlockAppender() { const { blockClientIds, renderAppender } = this.props; + return renderAppender && blockClientIds.length > 0; } render() { + const { isRootList } = this.props; + + // Use of Context to propagate the main scroll ref to its children e.g InnerBlocks + return isRootList ? ( + + { this.renderList() } + + ) : ( + + { ( ref ) => + this.renderList( { + parentScrollRef: ref, + } ) + } + + ); + } + + renderList( extraProps = {} ) { const { clearSelectedBlock, blockClientIds, title, header, - withFooter = true, isReadOnly, isRootList, + horizontal, shouldShowInsertionPointBefore, shouldShowInsertionPointAfter, + marginVertical = styles.defaultBlock.marginTop, + marginHorizontal = styles.defaultBlock.marginLeft, + isFloatingToolbarVisible, + isStackedHorizontally, + horizontalAlignment, } = this.props; + const { parentScrollRef } = extraProps; - const { blockToolbar, blockBorder, headerToolbar } = styles; + const { + blockToolbar, + blockBorder, + headerToolbar, + floatingToolbar, + } = styles; const forceRefresh = shouldShowInsertionPointBefore || shouldShowInsertionPointAfter; + const containerStyle = { + flex: isRootList ? 1 : 0, + // We set negative margin in the parent to remove the edge spacing between parent block and child block in ineer blocks + marginVertical: isRootList ? 0 : -marginVertical, + marginHorizontal: isRootList ? 0 : -marginHorizontal, + }; + return ( { + this.scrollViewInnerRef( parentScrollRef || ref ); + } } extraScrollHeight={ blockToolbar.height + blockBorder.width } - inputAccessoryViewHeight={ headerToolbar.height } + inputAccessoryViewHeight={ + headerToolbar.height + + ( isFloatingToolbarVisible + ? floatingToolbar.height + : 0 ) + } keyboardShouldPersistTaps="always" - scrollViewStyle={ { flex: isRootList ? 1 : 0 } } + scrollViewStyle={ [ + { flex: isRootList ? 1 : 0 }, + ! isRootList && styles.overflowVisible, + ] } + horizontal={ horizontal } + scrollEnabled={ isRootList } + contentContainerStyle={ + horizontal && styles.horizontalContentContainer + } + style={ [ + ! isRootList && styles.overflowVisible, + isStackedHorizontally && styles.horizontal, + horizontalAlignment && + styles[ `is-aligned-${ horizontalAlignment }` ], + ] } data={ blockClientIds } keyExtractor={ identity } extraData={ forceRefresh } @@ -135,13 +198,17 @@ export class BlockList extends Component { ListEmptyComponent={ ! isReadOnly && this.renderDefaultBlockAppender } - ListFooterComponent={ - ! isReadOnly && withFooter && this.renderBlockListFooter - } + ListFooterComponent={ this.renderBlockListFooter } /> { this.shouldShowInnerBlockAppender() && ( - + - + + { shouldShowInsertionPointBefore( clientId ) && ( ) } @@ -170,10 +251,17 @@ export class BlockList extends Component { key={ clientId } showTitle={ false } clientId={ clientId } + marginVertical={ marginVertical } + marginHorizontal={ marginHorizontal } rootClientId={ this.props.rootClientId } onCaretVerticalPositionChange={ this.onCaretVerticalPositionChange } + parentWidth={ this.props.parentWidth } + isStackedHorizontally={ isStackedHorizontally } + contentStyle={ contentStyle } + onAddBlock={ onAddBlock } + onDeleteBlock={ onDeleteBlock } /> { ! this.shouldShowInnerBlockAppender() && shouldShowInsertionPointAfter( clientId ) && ( @@ -186,23 +274,34 @@ export class BlockList extends Component { renderBlockListFooter() { const paragraphBlock = createBlock( 'core/paragraph' ); - return ( - <> - { - this.addBlockToEndOfPost( paragraphBlock ); - } } - > - - - - ); + const { + isReadOnly, + withFooter = true, + renderFooterAppender, + } = this.props; + + if ( ! isReadOnly && withFooter ) { + return ( + <> + { + this.addBlockToEndOfPost( paragraphBlock ); + } } + > + + + + ); + } else if ( renderFooterAppender ) { + return renderFooterAppender(); + } + return null; } } export default compose( [ - withSelect( ( select, { rootClientId } ) => { + withSelect( ( select, { rootClientId, __experimentalMoverDirection } ) => { const { getBlockCount, getBlockOrder, @@ -210,14 +309,19 @@ export default compose( [ getBlockInsertionPoint, isBlockInsertionPointVisible, getSettings, + getBlockHierarchyRootClientId, } = select( 'core/block-editor' ); + const isStackedHorizontally = + __experimentalMoverDirection === 'horizontal'; + const selectedBlockClientId = getSelectedBlockClientId(); const blockClientIds = getBlockOrder( rootClientId ); const insertionPoint = getBlockInsertionPoint(); const blockInsertionPointIsVisible = isBlockInsertionPointVisible(); const shouldShowInsertionPointBefore = ( clientId ) => { return ( + ! isStackedHorizontally && blockInsertionPointIsVisible && insertionPoint.rootClientId === rootClientId && // if list is empty, show the insertion point (via the default appender) @@ -228,6 +332,7 @@ export default compose( [ }; const shouldShowInsertionPointAfter = ( clientId ) => { return ( + ! isStackedHorizontally && blockInsertionPointIsVisible && insertionPoint.rootClientId === rootClientId && // if the insertion point is at the end of the list @@ -239,6 +344,14 @@ export default compose( [ const isReadOnly = getSettings().readOnly; + const rootBlockId = getBlockHierarchyRootClientId( + selectedBlockClientId + ); + const hasRootInnerBlocks = !! getBlockCount( rootBlockId ); + + const isFloatingToolbarVisible = + !! selectedBlockClientId && hasRootInnerBlocks; + return { blockClientIds, blockCount: getBlockCount( rootClientId ), @@ -248,6 +361,8 @@ export default compose( [ selectedBlockClientId, isReadOnly, isRootList: rootClientId === undefined, + isFloatingToolbarVisible, + isStackedHorizontally, }; } ), withDispatch( ( dispatch ) => { diff --git a/packages/block-editor/src/components/block-list/insertion-point.js b/packages/block-editor/src/components/block-list/insertion-point.js index 7aa46530ad3878..3d23ad7da4431b 100644 --- a/packages/block-editor/src/components/block-list/insertion-point.js +++ b/packages/block-editor/src/components/block-list/insertion-point.js @@ -49,7 +49,6 @@ function Indicator( { clientId } ) { } export default function InsertionPoint( { - className, isMultiSelecting, hasMultiSelection, selectedBlockClientId, @@ -72,7 +71,11 @@ export default function InsertionPoint( { } ); function onMouseMove( event ) { - if ( event.target.className !== className ) { + if ( + ! event.target.classList.contains( + 'block-editor-block-list__layout' + ) + ) { if ( isInserterShown ) { setIsInserterShown( false ); } @@ -177,7 +180,10 @@ export default function InsertionPoint( { } ) } > - +
diff --git a/packages/block-editor/src/components/block-list/moving-animation.js b/packages/block-editor/src/components/block-list/moving-animation.js index 6af4ba78ea6348..c4fa6a46fc2d14 100644 --- a/packages/block-editor/src/components/block-list/moving-animation.js +++ b/packages/block-editor/src/components/block-list/moving-animation.js @@ -10,7 +10,7 @@ import { useState, useLayoutEffect, useReducer, - useMemo, + useRef, } from '@wordpress/element'; import { useReducedMotion } from '@wordpress/compose'; import { getScrollContainer } from '@wordpress/dom'; @@ -69,12 +69,7 @@ function useMovingAnimation( } ); const previous = ref.current ? getAbsolutePosition( ref.current ) : null; - const scrollContainer = useMemo( () => { - if ( ! adjustScrolling ) { - return false; - } - return getScrollContainer( ref.current ); - }, [ adjustScrolling ] ); + const scrollContainer = useRef(); useLayoutEffect( () => { if ( triggeredAnimation ) { @@ -82,14 +77,17 @@ function useMovingAnimation( } }, [ triggeredAnimation ] ); useLayoutEffect( () => { + scrollContainer.current = getScrollContainer( ref.current ); if ( prefersReducedMotion ) { - if ( adjustScrolling && scrollContainer ) { + if ( adjustScrolling && scrollContainer.current && previous ) { // if the animation is disabled and the scroll needs to be adjusted, // just move directly to the final scroll position ref.current.style.transform = 'none'; const destination = getAbsolutePosition( ref.current ); - scrollContainer.scrollTop = - scrollContainer.scrollTop - previous.top + destination.top; + scrollContainer.current.scrollTop = + scrollContainer.current.scrollTop - + previous.top + + destination.top; } return; @@ -100,8 +98,10 @@ function useMovingAnimation( x: previous ? previous.left - destination.left : 0, y: previous ? previous.top - destination.top : 0, scrollTop: - previous && scrollContainer - ? scrollContainer.scrollTop - previous.top + destination.top + previous && scrollContainer.current + ? scrollContainer.current.scrollTop - + previous.top + + destination.top : 0, }; ref.current.style.transform = @@ -127,11 +127,12 @@ function useMovingAnimation( onFrame: ( props ) => { if ( adjustScrolling && - scrollContainer && + scrollContainer.current && ! prefersReducedMotion && props.y ) { - scrollContainer.scrollTop = transform.scrollTop + props.y; + scrollContainer.current.scrollTop = + transform.scrollTop + props.y; } }, } ); diff --git a/packages/block-editor/src/components/block-list/root-container.js b/packages/block-editor/src/components/block-list/root-container.js index 57bc4ff137459c..89569ab0a90444 100644 --- a/packages/block-editor/src/components/block-list/root-container.js +++ b/packages/block-editor/src/components/block-list/root-container.js @@ -1,3 +1,8 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + /** * WordPress dependencies */ @@ -46,7 +51,7 @@ function onDragStart( event ) { } } -function RootContainer( { children, className, hasPopover = true }, ref ) { +function RootContainer( { children, className }, ref ) { const { selectedBlockClientId, hasMultiSelection, @@ -76,17 +81,16 @@ function RootContainer( { children, className, hasPopover = true }, ref ) { return ( - { hasPopover ? : null } +
diff --git a/packages/block-editor/src/components/block-list/style.native.scss b/packages/block-editor/src/components/block-list/style.native.scss index 30b6ecc1dc5458..f2b07c5226916e 100644 --- a/packages/block-editor/src/components/block-list/style.native.scss +++ b/packages/block-editor/src/components/block-list/style.native.scss @@ -4,6 +4,16 @@ background-color: #fff; } +.horizontalContentContainer { + flex-direction: row; + flex-wrap: wrap; + justify-content: space-between; + align-items: stretch; + max-width: $content-width; + overflow: visible; + width: 100%; +} + .switch { flex-direction: row; justify-content: flex-start; @@ -47,9 +57,16 @@ height: 80px; } -.paddingToContent { - padding-left: $block-custom-appender-to-content; - padding-right: $block-custom-appender-to-content; +.defaultBlock { + margin: $block-edge-to-content; +} + +.defaultAppender { + margin: $block-edge-to-content; +} + +.innerAppender { + margin: $block-edge-to-content / 2; } .blockBorder { @@ -63,3 +80,28 @@ .blockToolbar { height: $mobile-block-toolbar-height; } + +.floatingToolbar { + height: $mobile-floating-toolbar-height + 2 * $mobile-floating-toolbar-margin; +} + +.horizontal { + flex-direction: row; + flex-wrap: wrap; +} + +.is-aligned-left { + justify-content: flex-start; +} + +.is-aligned-center { + justify-content: center; +} + +.is-aligned-right { + justify-content: flex-end; +} + +.overflowVisible { + overflow: visible; +} diff --git a/packages/block-editor/src/components/block-list/style.scss b/packages/block-editor/src/components/block-list/style.scss index 2d90124cce0011..f7dc606b69cb15 100644 --- a/packages/block-editor/src/components/block-list/style.scss +++ b/packages/block-editor/src/components/block-list/style.scss @@ -1,3 +1,8 @@ +.block-editor-block-list__block { + margin-left: auto; + margin-right: auto; +} + .block-editor-block-list__layout .block-editor-block-list__block { // Needs specificity to override inherited styles. // While block is being dragged, dim the slot dragged from, and hide some UI. &.is-dragging { @@ -21,33 +26,6 @@ margin: 0; } -/** - * General Post Content Layout - */ - -// Add side padding for the main block container, currently post_content. -// The purpose of this padding is to ensure that on small viewports, there is -// room for the block border that sits 14px ($block-padding) offset from the -// block footprint, as well as the side-UI. -.block-editor-block-list__layout { - padding-left: $block-padding; - padding-right: $block-padding; - position: relative; - - // Beyond the mobile breakpoint, compensate for side UI. - @include break-small() { - padding-left: $block-padding + $block-side-ui-width + $block-padding + $border-width * 2; - padding-right: $block-padding + $block-side-ui-width + $block-padding + $border-width * 2; - } - - // Don't propogate that padding to nested blocks. - .block-editor-block-list__layout { - padding-left: 0; - padding-right: 0; - } -} - - /** * Notices & Block Selected/Hover Styles. */ @@ -96,18 +74,18 @@ z-index: 1; pointer-events: none; content: ""; - top: 0; - bottom: 0; - left: 0; - right: 0; + top: $border-width; + bottom: $border-width; + left: $border-width; + right: $border-width; // 2px outside. - box-shadow: 0 0 0 2px $blue-medium-focus; - border-radius: $radius-block-ui; + box-shadow: 0 0 0 $border-width-focus $blue-medium-focus; + border-radius: $radius-block-ui - $border-width; // Border is outset, so so subtract the width to achieve correct radius. // Show a light color for dark themes. .is-dark-theme & { - box-shadow: 0 0 0 2px $blue-medium-focus-dark; + box-shadow: 0 0 0 $border-width-focus $blue-medium-focus-dark; } } } @@ -145,10 +123,12 @@ */ .block-editor-block-list__layout { + position: relative; // The primary indicator of selection in text is the native selection marker. // When selecting multiple blocks, we provide an additional selection indicator. .is-navigate-mode & .block-editor-block-list__block.is-selected, + .block-editor-block-list__block.is-highlighted, .block-editor-block-list__block.is-multi-selected { // Show selection borders around every non-nested block's actual footprint. @@ -157,24 +137,26 @@ z-index: 1; pointer-events: none; content: ""; - top: 0; - bottom: 0; - left: 0; - right: 0; + top: $border-width; + bottom: $border-width; + left: $border-width; + right: $border-width; } .is-block-content, // Floats. &::after { // Everything else. // 2px outside. - box-shadow: 0 0 0 2px $blue-medium-focus; - border-radius: $radius-block-ui; + box-shadow: 0 0 0 $border-width-focus $blue-medium-focus; + border-radius: $radius-block-ui - $border-width; // Border is outset, so so subtract the width to achieve correct radius. + transition: box-shadow 0.2s ease-out; + @include reduce-motion("transition"); // Windows High Contrast mode will show this outline. outline: 2px solid transparent; // Show a lighter color for dark themes. .is-dark-theme & { - box-shadow: 0 0 0 2px $blue-medium-focus-dark; + box-shadow: 0 0 0 $border-width-focus $blue-medium-focus-dark; } } @@ -203,6 +185,20 @@ min-height: ( $block-padding + $block-spacing ) * 2; } + &::after { + content: ""; + pointer-events: none; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + border-radius: $radius-block-ui; + box-shadow: 0 0 0 $border-width-focus transparent; + transition: box-shadow 0.1s ease-in; + @include reduce-motion("transition"); + } + // Warnings &.has-warning { // When a block has a warning, you shouldn't be able to manipulate the contents. @@ -299,18 +295,6 @@ clear: both; } - // Full-wide. - &[data-align="full"], - &.alignfull { - margin-left: -$block-padding; - margin-right: -$block-padding; - - @include break-small() { - margin-left: -$block-padding - $block-padding - $block-side-ui-width - $border-width - $border-width; - margin-right: -$block-padding - $block-padding - $block-side-ui-width - $border-width - $border-width; - } - } - // Clear floats. &[data-clear="true"] { float: none; @@ -336,7 +320,7 @@ cursor: grab; } -// Insertion point (includes inbetween inserter and insertion indicator) +// Insertion point (includes inbetween/sibling inserter and insertion indicator) .block-editor-block-list__insertion-point { position: relative; z-index: z-index(".block-editor-block-list__insertion-point"); @@ -346,7 +330,7 @@ .block-editor-block-list__insertion-point-indicator { position: absolute; top: calc(50% - #{ $border-width }); - height: 2px; + height: $border-width-focus; left: 0; right: 0; background: theme(primary); @@ -411,12 +395,6 @@ animation: block-editor-inserter__toggle__fade-in-animation-delayed 1.2s ease; animation-fill-mode: forwards; @include reduce-motion("animation"); - - &:hover { - animation: block-editor-inserter__toggle__fade-in-animation 0.2s ease; - animation-fill-mode: forwards; - @include reduce-motion("animation"); - } } } @@ -435,12 +413,30 @@ @keyframes block-editor-inserter__toggle__fade-in-animation { from { opacity: 0; + transform: scale(0); } to { opacity: 1; + transform: scale(1); } } +// Hide the appender that sits at the end of block lists, when inside a nested block, +// unless the block itself, or a parent, is selected. +.wp-block .block-list-appender .block-editor-inserter__toggle { + animation: block-editor-inserter__toggle__fade-in-animation 0.1s ease; + animation-fill-mode: forwards; + @include reduce-motion("animation"); +} + +.wp-block:not(.is-selected):not(.has-child-selected) .block-editor-default-block-appender { + display: none; + + .block-editor-inserter__toggle { + opacity: 0; + transform: scale(0); + } +} // This is the edge-to-edge hover area that contains the plus. .block-editor-block-list__block { @@ -486,21 +482,6 @@ padding-left: $block-toolbar-height; // Provide space for the mover control on full-wide items. } -.edit-post-header-toolbar__block-toolbar, -.block-editor-block-contextual-toolbar { - // Adapt the height of the toolbar items. - .components-toolbar { - height: $block-toolbar-height; - background: none; - } - - // Adapt the height of all toolbar buttons. - .components-button { - height: $block-toolbar-height; - } -} - - /** * Block Toolbar when contextual. */ @@ -525,30 +506,28 @@ display: block; z-index: z-index(".block-editor-block-list__breadcrumb"); - .components-toolbar { - display: flex; - border: none; - background: none; + // The button here has a special style to appear as a toolbar. + .components-button { + font-size: $default-font-size; + height: $block-toolbar-height - $border-width - $border-width; + padding: $grid-unit-15 $grid-unit-20; - // The button here has a special style to appear as a toolbar. - .components-button { - font-size: $default-font-size; - height: $block-toolbar-height; - padding: $grid-unit-15 $grid-unit-20; - - // Block UI appearance. - border: $border-width solid $dark-gray-primary; - border-radius: $radius-block-ui; - background-color: $white; - - // When button is focused, it receives a box-shadow instead of the border. - &:focus { - border: none; - box-shadow: inset 0 0 0 1px color($theme-color), 0 0 0 1px color($theme-color); - } - } + // Position this to align with the block toolbar. + position: relative; + top: -$border-width; - // @todo, it should have the block type icon here. + // Block UI appearance. + box-shadow: 0 0 0 $border-width $dark-gray-primary; + border-radius: $radius-block-ui - $border-width; // Border is outset, so so subtract the width to achieve correct radius. + background-color: $white; + + // Indent to align with block toolbar. + margin-left: $block-toolbar-height + $border-width; + + // When button is focused, it receives a box-shadow instead of the border. + &:focus { + box-shadow: 0 0 0 $border-width-focus $theme-color; + } } } @@ -610,11 +589,8 @@ // Position the block toolbar. .block-editor-block-list__breadcrumb, .block-editor-block-contextual-toolbar { - margin-bottom: $grid-unit-20; - - // @todo It should position the block transform dialog as the left margin of a block. It currently - // positions instead, the mover control. - margin-left: - $block-toolbar-height - $border-width; + margin-bottom: $grid-unit-15; + margin-left: - $block-toolbar-height; } .block-editor-block-contextual-toolbar[data-align="full"], @@ -631,3 +607,35 @@ .is-dragging-components-draggable .components-tooltip { display: none; } + + +// Add side padding for the canvas, currently edit-post-visual-editor. +// The purpose of this padding is to ensure that on small viewports, there is +// room for the block border that sits 14px ($block-padding) offset from the +// block footprint. +// These paddings and margins are removed from the BlockPreview component's style +// Any change need to be reflected there. +.block-editor-block-list__layout.is-root-container { + padding-left: $block-padding; + padding-right: $block-padding; + + @include break-small() { + padding-left: $block-side-ui-width; + padding-right: $block-side-ui-width; + } + + // Full-wide. (to account for the padddings added above) + // The first two rules account for the alignment wrapper div for the image block. + > div:not(.block-editor-block-list__block) > .block-editor-block-list__block[data-align="full"], + > div:not(.block-editor-block-list__block) > .block-editor-block-list__block.alignfull, + > .block-editor-block-list__block[data-align="full"], + > .block-editor-block-list__block.alignfull { + margin-left: -$block-padding; + margin-right: -$block-padding; + + @include break-small() { + margin-left: -$block-side-ui-width; + margin-right: -$block-side-ui-width; + } + } +} diff --git a/packages/block-editor/src/components/block-list/subdirectory-icon.js b/packages/block-editor/src/components/block-list/subdirectory-icon.js index f024c51880e4b2..432f545e4524d8 100644 --- a/packages/block-editor/src/components/block-list/subdirectory-icon.js +++ b/packages/block-editor/src/components/block-list/subdirectory-icon.js @@ -3,7 +3,7 @@ */ import { SVG, Path } from '@wordpress/components'; -const Subdirectory = ( { ...extraProps } ) => ( +const Subdirectory = ( { isRTL, ...extraProps } ) => ( ( viewBox="0 0 20 20" { ...extraProps } > - + ); export default Subdirectory; diff --git a/packages/block-editor/src/components/block-list/use-multi-selection.js b/packages/block-editor/src/components/block-list/use-multi-selection.js index 1e77f8711a51de..2d40464f2c0c56 100644 --- a/packages/block-editor/src/components/block-list/use-multi-selection.js +++ b/packages/block-editor/src/components/block-list/use-multi-selection.js @@ -105,8 +105,9 @@ export default function useMultiSelection( ref ) { ); if ( - ! blockNode.contains( startContainer ) || - ! blockNode.contains( endContainer ) + !! blockNode && + ( ! blockNode.contains( startContainer ) || + ! blockNode.contains( endContainer ) ) ) { selection.removeAllRanges(); } diff --git a/packages/block-editor/src/components/block-mobile-toolbar/index.native.js b/packages/block-editor/src/components/block-mobile-toolbar/index.native.js index 43a34c0466b54d..6e3fc8aaa1fdd2 100644 --- a/packages/block-editor/src/components/block-mobile-toolbar/index.native.js +++ b/packages/block-editor/src/components/block-mobile-toolbar/index.native.js @@ -19,9 +19,17 @@ import styles from './style.scss'; import BlockMover from '../block-mover'; import { BlockSettingsButton } from '../block-settings'; -const BlockMobileToolbar = ( { clientId, onDelete, order } ) => ( +const BlockMobileToolbar = ( { + clientId, + onDelete, + order, + isStackedHorizontally, +} ) => ( - + @@ -48,13 +56,15 @@ export default compose( order: getBlockIndex( clientId ), }; } ), - withDispatch( ( dispatch, { clientId, rootClientId } ) => { + withDispatch( ( dispatch, { clientId, rootClientId, onDelete } ) => { const { removeBlock } = dispatch( 'core/block-editor' ); return { - onDelete: () => { - Keyboard.dismiss(); - removeBlock( clientId, rootClientId ); - }, + onDelete: + onDelete || + ( () => { + Keyboard.dismiss(); + removeBlock( clientId, rootClientId ); + } ), }; } ) )( BlockMobileToolbar ); diff --git a/packages/block-editor/src/components/block-mover/index.native.js b/packages/block-editor/src/components/block-mover/index.native.js index b572e21ee79dd8..818d7b35f3ac23 100644 --- a/packages/block-editor/src/components/block-mover/index.native.js +++ b/packages/block-editor/src/components/block-mover/index.native.js @@ -1,6 +1,7 @@ /** * External dependencies */ +import { I18nManager } from 'react-native'; import { first, last, partial, castArray } from 'lodash'; /** @@ -10,58 +11,124 @@ import { ToolbarButton } from '@wordpress/components'; import { __, sprintf } from '@wordpress/i18n'; import { withSelect, withDispatch } from '@wordpress/data'; import { withInstanceId, compose } from '@wordpress/compose'; -import { arrowUp, arrowDown } from '@wordpress/icons'; +import { arrowUp, arrowDown, arrowLeft, arrowRight } from '@wordpress/icons'; + +const horizontalMover = { + backwardButtonIcon: arrowLeft, + forwardButtonIcon: arrowRight, + backwardButtonHint: __( 'Double tap to move the block to the left' ), + forwardButtonHint: __( 'Double tap to move the block to the right' ), + firstBlockTitle: __( 'Move block left' ), + lastBlockTitle: __( 'Move block right' ), + /* translators: accessibility text. %1: current block position (number). %2: next block position (number) */ + backwardButtonTitle: __( + 'Move block left from position %1$s to position %2$s' + ), + /* translators: accessibility text. %1: current block position (number). %2: next block position (number) */ + forwardButtonTitle: __( + 'Move block right from position %1$s to position %2$s' + ), +}; + +const verticalMover = { + backwardButtonIcon: arrowUp, + forwardButtonIcon: arrowDown, + backwardButtonHint: __( 'Double tap to move the block up' ), + forwardButtonHint: __( 'Double tap to move the block down' ), + firstBlockTitle: __( 'Move block up' ), + lastBlockTitle: __( 'Move block down' ), + /* translators: accessibility text. %1: current block position (number). %2: next block position (number) */ + backwardButtonTitle: __( 'Move block up from row %1$s to row %2$s' ), + /* translators: accessibility text. %1: current block position (number). %2: next block position (number) */ + forwardButtonTitle: __( 'Move block down from row %1$s to row %2$s' ), +}; const BlockMover = ( { isFirst, isLast, + isRTL, isLocked, onMoveDown, onMoveUp, firstIndex, rootClientId, + isStackedHorizontally, } ) => { + const { + backwardButtonIcon, + forwardButtonIcon, + backwardButtonHint, + forwardButtonHint, + firstBlockTitle, + lastBlockTitle, + } = isStackedHorizontally ? horizontalMover : verticalMover; + if ( isLocked || ( isFirst && isLast && ! rootClientId ) ) { return null; } + const switchButtonPropIfRTL = ( + isBackwardButton, + forwardButtonProp, + backwardButtonProp + ) => { + if ( isRTL && isStackedHorizontally ) { + // for RTL and horizontal direction switch prop between forward and backward button + if ( isBackwardButton ) { + return forwardButtonProp; // set forwardButtonProp for backward button + } + return backwardButtonProp; // set backwardButtonProp for forward button + } + + return isBackwardButton ? backwardButtonProp : forwardButtonProp; + }; + + const getMoverButtonTitle = ( isBackwardButton ) => { + const fromIndex = firstIndex + 1; // current position based on index + // for backwardButton decrease index (move left/up) for forwardButton increase index (move right/down) + const direction = isBackwardButton ? -1 : 1; + const toIndex = fromIndex + direction; // position after move + + const { + backwardButtonTitle, + forwardButtonTitle, + } = isStackedHorizontally ? horizontalMover : verticalMover; + + const buttonTitle = switchButtonPropIfRTL( + isBackwardButton, + forwardButtonTitle, + backwardButtonTitle + ); + + return sprintf( buttonTitle, fromIndex, toIndex ); + }; + + const getArrowIcon = ( isBackwardButton ) => + switchButtonPropIfRTL( + isBackwardButton, + forwardButtonIcon, + backwardButtonIcon + ); + return ( <> @@ -90,6 +157,7 @@ export default compose( firstIndex, isFirst: firstIndex === 0, isLast: lastIndex === blockOrder.length - 1, + isRTL: I18nManager.isRTL, isLocked: getTemplateLock( rootClientId ) === 'all', rootClientId, }; diff --git a/packages/block-editor/src/components/block-mover/mover-description.js b/packages/block-editor/src/components/block-mover/mover-description.js index 88e67e5ff4a715..fbdc10cb256138 100644 --- a/packages/block-editor/src/components/block-mover/mover-description.js +++ b/packages/block-editor/src/components/block-mover/mover-description.js @@ -58,8 +58,8 @@ export function getBlockMoverDescription( } if ( isFirst && isLast ) { - // translators: %s: Type of block (i.e. Text, Image etc) return sprintf( + // translators: %s: Type of block (i.e. Text, Image etc) __( 'Block %s is the only block, and cannot be moved' ), type ); diff --git a/packages/block-editor/src/components/block-mover/style.scss b/packages/block-editor/src/components/block-mover/style.scss index 83dcf5c459fe60..e60bbcaacdb902 100644 --- a/packages/block-editor/src/components/block-mover/style.scss +++ b/packages/block-editor/src/components/block-mover/style.scss @@ -21,6 +21,10 @@ flex-direction: row; } + .block-editor-block-mover__control { + height: $block-toolbar-height/2; + } + // Position the icons correctly. .components-toolbar .block-editor-block-mover__control-up { svg { diff --git a/packages/block-editor/src/components/block-navigation/style.scss b/packages/block-editor/src/components/block-navigation/style.scss index 6a6f47e7250561..abc9ad802ed08e 100644 --- a/packages/block-editor/src/components/block-navigation/style.scss +++ b/packages/block-editor/src/components/block-navigation/style.scss @@ -81,10 +81,12 @@ $tree-item-height: 36px; margin-right: 6px; } - &.is-selected, - &.is-selected:focus { + &.is-selected svg, + &.is-selected:focus svg { color: $white; background: $dark-gray-primary; + box-shadow: 0 0 0 $border-width $dark-gray-primary; + border-radius: $border-width; } } diff --git a/packages/block-editor/src/components/block-patterns/style.scss b/packages/block-editor/src/components/block-patterns/style.scss deleted file mode 100644 index f40f46b04001cb..00000000000000 --- a/packages/block-editor/src/components/block-patterns/style.scss +++ /dev/null @@ -1,30 +0,0 @@ -.block-editor-patterns { - padding: 16px; -} - -.block-editor-patterns__item { - border-radius: 2px; - cursor: pointer; - margin-bottom: 16px; - border: 1px solid $light-gray-500; - transition: all 0.05s ease-in-out; - position: relative; - - &:hover { - background: $white; - box-shadow: 0 0 0 1px $white, 0 0 0 3px $dark-gray-500; - } - - &:focus { - @include block-style__focus(); - } -} - -.block-editor-patterns__item-preview { - padding: $grid-unit-20; -} - -.block-editor-patterns__item-title { - text-align: center; - padding: 10px 0; -} diff --git a/packages/block-editor/src/components/block-preview/auto.js b/packages/block-editor/src/components/block-preview/auto.js index 81d26ada36d111..b02b362390e46a 100644 --- a/packages/block-editor/src/components/block-preview/auto.js +++ b/packages/block-editor/src/components/block-preview/auto.js @@ -2,14 +2,17 @@ * WordPress dependencies */ import { Disabled } from '@wordpress/components'; -import { useResizeObserver } from '@wordpress/compose'; +import { useResizeObserver, pure } from '@wordpress/compose'; /** * Internal dependencies */ import BlockList from '../block-list'; -function AutoBlockPreview( { viewportWidth } ) { +// This is used to avoid rendering the block list if the sizes change. +const MemoizedBlockList = pure( BlockList ); + +function AutoBlockPreview( { viewportWidth, __experimentalPadding } ) { const [ containerResizeListener, { width: containerWidth }, @@ -19,24 +22,30 @@ function AutoBlockPreview( { viewportWidth } ) { { height: contentHeight }, ] = useResizeObserver(); + const scale = + ( containerWidth - 2 * __experimentalPadding ) / viewportWidth; + return (
{ containerResizeListener } { containtResizeListener } - +
); diff --git a/packages/block-editor/src/components/block-preview/index.js b/packages/block-editor/src/components/block-preview/index.js index 522bd6014282bc..d49fad67dac347 100644 --- a/packages/block-editor/src/components/block-preview/index.js +++ b/packages/block-editor/src/components/block-preview/index.js @@ -1,19 +1,18 @@ /** * External dependencies */ -import { castArray, noop } from 'lodash'; +import { castArray } from 'lodash'; /** * WordPress dependencies */ import { useSelect } from '@wordpress/data'; -import { useLayoutEffect, useReducer, useMemo } from '@wordpress/element'; +import { useMemo } from '@wordpress/element'; /** * Internal dependencies */ import BlockEditorProvider from '../provider'; -import ScaledBlockPreview from './scaled'; import AutoHeightBlockPreview from './auto'; /** @@ -21,52 +20,30 @@ import AutoHeightBlockPreview from './auto'; * * @see https://github.com/WordPress/gutenberg/blob/master/packages/block-editor/src/components/block-preview/README.md * - * @param {Array|Object} blocks A block instance (object) or an array of blocks to be previewed. - * @param {number} viewportWidth Width of the preview container in pixels. Controls at what size the blocks will be rendered inside the preview. Default: 700. + * @param {Object} preview options for how the preview should be shown + * @param {Array|Object} preview.blocks A block instance (object) or an array of blocks to be previewed. + * @param {number} preview.viewportWidth Width of the preview container in pixels. Controls at what size the blocks will be rendered inside the preview. Default: 700. + * * @return {WPComponent} The component to be rendered. */ export function BlockPreview( { blocks, + __experimentalPadding = 0, viewportWidth = 700, - padding, - autoHeight = false, - __experimentalOnReady = noop, - __experimentalScalingDelay = 100, } ) { const settings = useSelect( ( select ) => select( 'core/block-editor' ).getSettings() ); const renderedBlocks = useMemo( () => castArray( blocks ), [ blocks ] ); - const [ recompute, triggerRecompute ] = useReducer( - ( state ) => state + 1, - 0 - ); - useLayoutEffect( triggerRecompute, [ blocks ] ); if ( ! blocks || blocks.length === 0 ) { return null; } return ( - { /* - * The key prop is used to force recomputing the preview - * by remounting the component, ScaledBlockPreview is not meant to - * be rerendered. - */ } - { autoHeight ? ( - - ) : ( - - ) } + ); } diff --git a/packages/block-editor/src/components/block-preview/scaled.js b/packages/block-editor/src/components/block-preview/scaled.js deleted file mode 100644 index 69496241fdb5ac..00000000000000 --- a/packages/block-editor/src/components/block-preview/scaled.js +++ /dev/null @@ -1,155 +0,0 @@ -/** - * External dependencies - */ -import classnames from 'classnames'; - -/** - * WordPress dependencies - */ -import { Disabled } from '@wordpress/components'; -import { useLayoutEffect, useState, useRef } from '@wordpress/element'; - -/** - * Internal dependencies - */ -import BlockList from '../block-list'; -import { getBlockPreviewContainerDOMNode } from '../../utils/dom'; - -const getInlineStyles = ( scale, x, y, isReady, width ) => ( { - transform: `scale(${ scale })`, - visibility: isReady ? 'visible' : 'hidden', - left: x, - top: y, - width, -} ); - -function ScaledBlockPreview( { - blocks, - viewportWidth, - padding = 0, - onReady, - scalingDelay, -} ) { - const previewRef = useRef( null ); - - const [ isReady, setIsReady ] = useState( false ); - const [ previewScale, setPreviewScale ] = useState( 1 ); - const [ { x, y }, setPosition ] = useState( { x: 0, y: 0 } ); - - // Dynamically calculate the scale factor - useLayoutEffect( () => { - // Timer - required to account for async render of `BlockEditorProvider` - const timerId = setTimeout( () => { - const containerElement = previewRef.current; - if ( ! containerElement ) { - return; - } - - // Auxiliary vars used for onReady() callback. - let scale, - offsetX = 0, - offsetY = 0; - - // If we're previewing a single block, scale the preview to fit it. - if ( blocks.length === 1 ) { - const block = blocks[ 0 ]; - const previewElement = getBlockPreviewContainerDOMNode( - block.clientId - ); - if ( ! previewElement ) { - return; - } - - let containerElementRect = containerElement.getBoundingClientRect(); - containerElementRect = { - width: containerElementRect.width - padding * 2, - height: containerElementRect.height - padding * 2, - left: containerElementRect.left, - top: containerElementRect.top, - }; - const scaledElementRect = previewElement.getBoundingClientRect(); - - scale = - containerElementRect.width / scaledElementRect.width || 1; - offsetX = - -( scaledElementRect.left - containerElementRect.left ) * - scale + - padding; - offsetY = - containerElementRect.height > - scaledElementRect.height * scale - ? ( containerElementRect.height - - scaledElementRect.height * scale ) / - 2 + - padding - : 0; - - setPreviewScale( scale ); - setPosition( { x: offsetX, y: offsetY } ); - - // Hack: we need to reset the scaled elements margins - previewElement.style.marginTop = '0'; - } else { - const containerElementRect = containerElement.getBoundingClientRect(); - scale = containerElementRect.width / viewportWidth; - setPreviewScale( scale ); - } - - setIsReady( true ); - onReady( { - scale, - position: { x: offsetX, y: offsetY }, - previewContainerRef: previewRef, - - inlineStyles: getInlineStyles( - scale, - offsetX, - offsetY, - true, - viewportWidth - ), - } ); - }, scalingDelay ); - - // Cleanup - return () => { - if ( timerId ) { - window.clearTimeout( timerId ); - } - }; - }, [] ); - - if ( ! blocks || blocks.length === 0 ) { - return null; - } - - const previewStyles = getInlineStyles( - previewScale, - x, - y, - isReady, - viewportWidth - ); - - return ( -
- - - -
- ); -} - -export default ScaledBlockPreview; diff --git a/packages/block-editor/src/components/block-preview/style.scss b/packages/block-editor/src/components/block-preview/style.scss index 1628c178dbd059..1d0df3962fd741 100644 --- a/packages/block-editor/src/components/block-preview/style.scss +++ b/packages/block-editor/src/components/block-preview/style.scss @@ -9,9 +9,6 @@ width: 100%; overflow: hidden; - &.is-ready { - overflow: visible; - } } .block-editor-block-preview__content { @@ -35,17 +32,25 @@ overflow: visible; min-height: auto; - .block-editor-block-preview__container &.is-centered { - .block-editor-block-list__layout, - .block-editor-block-list__block { - padding: 0; - } - } - .block-editor-block-list__insertion-point, .block-editor-block-drop-zone, .reusable-block-indicator, .block-list-appender { display: none; } + + // Reset default editor padding + .block-editor-block-list__layout.is-root-container { + padding-left: 0; + padding-right: 0; + + > div:not(.block-editor-block-list__block) > .block-editor-block-list__block[data-align="full"], + > div:not(.block-editor-block-list__block) > .block-editor-block-list__block.alignfull, + > .block-editor-block-list__block[data-align="full"], + > .block-editor-block-list__block.alignfull { + margin-left: 0; + margin-right: 0; + } + } } + diff --git a/packages/block-editor/src/components/block-settings-menu/index.js b/packages/block-editor/src/components/block-settings-menu/index.js index 278c3b79b0be32..e4c2c64682a32f 100644 --- a/packages/block-editor/src/components/block-settings-menu/index.js +++ b/packages/block-editor/src/components/block-settings-menu/index.js @@ -29,7 +29,7 @@ import BlockSettingsMenuControls from '../block-settings-menu-controls'; const POPOVER_PROPS = { className: 'block-editor-block-settings-menu__popover', position: 'bottom right', - noArrow: true, + isAlternate: true, }; export function BlockSettingsMenu( { clientIds } ) { diff --git a/packages/block-editor/src/components/block-styles/style.scss b/packages/block-editor/src/components/block-styles/style.scss index b84725cf707f35..ab720c9495d992 100644 --- a/packages/block-editor/src/components/block-styles/style.scss +++ b/packages/block-editor/src/components/block-styles/style.scss @@ -10,20 +10,20 @@ flex-shrink: 0; cursor: pointer; overflow: hidden; - border-radius: $radius-round-rectangle; + border-radius: $radius-block-ui; padding: $grid-unit-05 * 1.5; - padding-top: calc(50% * 0.75 - #{ $grid-unit-05 } * 1.5); + display: flex; + flex-direction: column; &:focus { - @include block-style__focus(); - } + box-shadow: 0 0 0 $border-width-focus $theme-color; - &:hover { - @include block-style__hover; + // Windows High Contrast mode will show this outline, but not the box-shadow. + outline: 2px solid transparent; + } - .block-editor-block-styles__item-preview { - border-color: $theme-color; - } + &:hover .block-editor-block-styles__item-preview { + border-color: $theme-color; } &.is-active { @@ -42,18 +42,13 @@ outline: $border-width solid transparent; // Shown in Windows High Contrast mode. padding: 0; border: $border-width solid rgba($dark-gray-primary, 0.2); - border-radius: $radius-round-rectangle; + border-radius: $radius-block-ui; display: flex; overflow: hidden; background: $white; - padding-top: 75%; - margin-top: -75%; - - .block-editor-block-preview__container { - padding-top: 0; - margin: 0; - margin-top: -75%; - } + align-items: center; + flex-grow: 1; + min-height: 80px; } .block-editor-block-styles__item-label { diff --git a/packages/block-editor/src/components/block-switcher/index.js b/packages/block-editor/src/components/block-switcher/index.js index e74cfc9ad94b76..eb2f7653af4f28 100644 --- a/packages/block-editor/src/components/block-switcher/index.js +++ b/packages/block-editor/src/components/block-switcher/index.js @@ -29,6 +29,11 @@ import BlockStyles from '../block-styles'; import BlockPreview from '../block-preview'; import BlockTypesList from '../block-types-list'; +const POPOVER_PROPS = { + position: 'bottom right', + isAlternate: true, +}; + export class BlockSwitcher extends Component { constructor() { super( ...arguments ); @@ -99,7 +104,7 @@ export class BlockSwitcher extends Component { return ( { @@ -114,6 +119,7 @@ export class BlockSwitcher extends Component { 1 === blocks.length ? __( 'Change block type or style' ) : sprintf( + /* translators: %s: number of blocks. */ _n( 'Change type of %d block', 'Change type of %d blocks', diff --git a/packages/block-editor/src/components/block-switcher/style.scss b/packages/block-editor/src/components/block-switcher/style.scss index 207acd240f0a45..17878a4db2963c 100644 --- a/packages/block-editor/src/components/block-switcher/style.scss +++ b/packages/block-editor/src/components/block-switcher/style.scss @@ -6,19 +6,6 @@ .block-editor-block-switcher__no-switcher-icon, .block-editor-block-switcher__toggle { position: relative; - - &::after { - display: block; - content: ""; - position: absolute; - bottom: 1px; - right: 0; - border-color: transparent; - border-style: solid; - border-width: 4px; - border-right-color: currentColor; - border-bottom-color: currentColor; - } } @@ -82,7 +69,6 @@ max-width: calc(340px * 2); display: flex; background: $white; - box-shadow: $shadow-popover; padding: 0; .components-menu-group { diff --git a/packages/block-editor/src/components/block-switcher/test/__snapshots__/index.js.snap b/packages/block-editor/src/components/block-switcher/test/__snapshots__/index.js.snap index ab8ff515675b62..a7a9d6dd1bbed0 100644 --- a/packages/block-editor/src/components/block-switcher/test/__snapshots__/index.js.snap +++ b/packages/block-editor/src/components/block-switcher/test/__snapshots__/index.js.snap @@ -29,7 +29,12 @@ exports[`BlockSwitcher should render enabled block switcher with multi block whe @@ -39,7 +44,12 @@ exports[`BlockSwitcher should render switcher with blocks 1`] = ` diff --git a/packages/block-editor/src/components/block-toolbar/index.js b/packages/block-editor/src/components/block-toolbar/index.js index 36b20c44e0fcba..d2dc21fff63c20 100644 --- a/packages/block-editor/src/components/block-toolbar/index.js +++ b/packages/block-editor/src/components/block-toolbar/index.js @@ -16,16 +16,16 @@ import BlockSwitcher from '../block-switcher'; import BlockControls from '../block-controls'; import BlockFormatControls from '../block-format-controls'; import BlockSettingsMenu from '../block-settings-menu'; -import { useShowMoversGestures } from './utils'; +import { useShowMoversGestures, useToggleBlockHighlight } from './utils'; export default function BlockToolbar( { hideDragHandle } ) { const { blockClientIds, + blockClientId, hasFixedToolbar, isValid, mode, moverDirection, - hasMovers = true, } = useSelect( ( select ) => { const { getBlockMode, @@ -36,15 +36,15 @@ export default function BlockToolbar( { hideDragHandle } ) { getSettings, } = select( 'core/block-editor' ); const selectedBlockClientIds = getSelectedBlockClientIds(); - const blockRootClientId = getBlockRootClientId( - selectedBlockClientIds[ 0 ] - ); + const selectedBlockClientId = selectedBlockClientIds[ 0 ]; + const blockRootClientId = getBlockRootClientId( selectedBlockClientId ); - const { __experimentalMoverDirection, __experimentalUIParts = {} } = + const { __experimentalMoverDirection } = getBlockListSettings( blockRootClientId ) || {}; return { blockClientIds: selectedBlockClientIds, + blockClientId: selectedBlockClientId, hasFixedToolbar: getSettings().hasFixedToolbar, rootClientId: blockRootClientId, isValid: @@ -56,22 +56,23 @@ export default function BlockToolbar( { hideDragHandle } ) { ? getBlockMode( selectedBlockClientIds[ 0 ] ) : null, moverDirection: __experimentalMoverDirection, - hasMovers: __experimentalUIParts.hasMovers, }; }, [] ); + const toggleBlockHighlight = useToggleBlockHighlight( blockClientId ); const nodeRef = useRef(); - const { - showMovers, - gestures: showMoversGestures, - } = useShowMoversGestures( { ref: nodeRef } ); + const { showMovers, gestures: showMoversGestures } = useShowMoversGestures( + { + ref: nodeRef, + onChange: toggleBlockHighlight, + } + ); const displayHeaderToolbar = useViewportMatch( 'medium', '<' ) || hasFixedToolbar; - const shouldShowMovers = - displayHeaderToolbar || ( showMovers && hasMovers ); + const shouldShowMovers = displayHeaderToolbar || showMovers; if ( blockClientIds.length === 0 ) { return null; diff --git a/packages/block-editor/src/components/block-toolbar/style.scss b/packages/block-editor/src/components/block-toolbar/style.scss index d03ae73ec64351..6cc37f4d9309d4 100644 --- a/packages/block-editor/src/components/block-toolbar/style.scss +++ b/packages/block-editor/src/components/block-toolbar/style.scss @@ -44,130 +44,11 @@ .block-editor-block-toolbar, .block-editor-format-toolbar { - // Toolbar buttons. - .components-button { - position: relative; - - // Give all buttons extra padding to fit text. - padding-left: $grid-unit-20; - padding-right: $grid-unit-20; - - // Don't show the focus inherited by the Button component. - &:focus:enabled { - box-shadow: none; - outline: none; - } - - // Focus and toggle pseudo elements. - &::before { - content: ""; - position: absolute; - display: block; - border-radius: $radius-block-ui; - height: 32px; - min-width: 32px; - - // Position the focus rectangle. - left: $grid-unit-10; - right: $grid-unit-10; - } - - svg { - position: relative; - - // Center the icon inside. - margin-left: auto; - margin-right: auto; - } - - // Toggled style. - &.is-pressed { - color: $white; - - &::before { - background: $dark-gray-primary; - } - } - - // Focus style. - &:focus::before { - @include block-toolbar-button-style__focus(); - } - - // Ensure the icon buttons remain square. - &.has-icon { - // Reduce the default padding when a button only has an icon. - padding-left: $grid-unit-10; - padding-right: $grid-unit-10; - - min-width: $block-toolbar-height; - justify-content: center; - } - - // @todo: We should extract the tabs styles to the tabs component itself - &.components-tab-button { - font-weight: 500; - - span { - display: inline-block; - padding-left: 0; - padding-right: 0; - position: relative; - } - } - } - - // Size multiple sequential buttons to be optically balanced. - // Icons are 36px, as set by a 24px icon and 12px padding. - .components-toolbar div > .components-button.has-icon { - min-width: $block-toolbar-height - $grid-unit-15; - padding-left: $grid-unit-15 / 2; // 6px. - padding-right: $grid-unit-15 / 2; - - svg { - min-width: $button-size-small; // This is the optimal icon size, and we size the whole button after this. - } - - &::before { - left: 2px; - right: 2px; - } - } - - // First button in a group. - .components-toolbar div:first-child .components-button { - min-width: $block-toolbar-height - $grid-unit-15 / 2; - padding-left: $grid-unit-15 - $border-width; - padding-right: $grid-unit-15 / 2; - - &::before { - left: $grid-unit-10; - right: 2px; - } - } - - // Last button in a group. - .components-toolbar div:last-child .components-button { - min-width: $block-toolbar-height - $grid-unit-15 / 2; - padding-left: $grid-unit-15 / 2; - padding-right: $grid-unit-15 - $border-width; - - &::before { - left: 2px; - right: $grid-unit-10; - } - } - - // Single buttons should remain 48px. - .components-toolbar div:first-child:last-child > .components-button { - min-width: $block-toolbar-height; - padding-left: $grid-unit-15; - padding-right: $grid-unit-15; - - &::before { - left: $grid-unit-10; - right: $grid-unit-10; - } + // Override Toolbar buttons size. + .components-toolbar-group, + .components-toolbar { + display: flex; + flex-wrap: nowrap; } } @@ -202,10 +83,19 @@ top: -1px; transform: translateX(-48px); user-select: none; - z-index: -1; // This makes it slide out from underneath the toolbar. } } + // Explicitly color the background of the switcher to "cover" the mover control as it animates out. + .block-editor-block-toolbar__block-switcher-wrapper { + background: $white; + border-left: $border-width solid; + border-radius: 0 0 $radius-block-ui $radius-block-ui; + position: relative; + z-index: 1; + margin-left: -$border-width; + } + .block-editor-block-toolbar__mover-trigger-wrapper:not(:empty) { @include break-medium() { background-color: $white; diff --git a/packages/block-editor/src/components/block-toolbar/utils.js b/packages/block-editor/src/components/block-toolbar/utils.js index da64ca0bfb3488..2ee4a65b0d43f5 100644 --- a/packages/block-editor/src/components/block-toolbar/utils.js +++ b/packages/block-editor/src/components/block-toolbar/utils.js @@ -1,9 +1,15 @@ +/** + * External dependencies + */ +import { noop } from 'lodash'; /** * WordPress dependencies */ +import { useDispatch } from '@wordpress/data'; import { useState, useRef, useEffect, useCallback } from '@wordpress/element'; -const { clearTimeout, setTimeout } = window; +const { clearTimeout, requestAnimationFrame, setTimeout } = window; +const DEBOUNCE_TIMEOUT = 250; /** * Hook that creates a showMover state, as well as debounced show/hide callbacks @@ -11,11 +17,17 @@ const { clearTimeout, setTimeout } = window; export function useDebouncedShowMovers( { ref, isFocused, - debounceTimeout = 500, + debounceTimeout = DEBOUNCE_TIMEOUT, + onChange = noop, } ) { const [ showMovers, setShowMovers ] = useState( false ); const timeoutRef = useRef(); + const handleOnChange = ( nextIsFocused ) => { + setShowMovers( nextIsFocused ); + onChange( nextIsFocused ); + }; + const getIsHovered = () => { return ref?.current && ref.current.matches( ':hover' ); }; @@ -26,40 +38,41 @@ export function useDebouncedShowMovers( { return ! isFocused && ! isHovered; }; - const debouncedShowMovers = useCallback( - ( event ) => { - if ( event ) { - event.stopPropagation(); - } + const clearTimeoutRef = () => { + const timeout = timeoutRef.current; - const timeout = timeoutRef.current; + if ( timeout && clearTimeout ) { + clearTimeout( timeout ); + } + }; - if ( timeout && clearTimeout ) { - clearTimeout( timeout ); - } - if ( ! showMovers ) { - setShowMovers( true ); - } - }, - [ showMovers ] - ); + const debouncedShowMovers = ( event ) => { + if ( event ) { + event.stopPropagation(); + } - const debouncedHideMovers = useCallback( - ( event ) => { - if ( event ) { - event.stopPropagation(); - } + clearTimeoutRef(); - timeoutRef.current = setTimeout( () => { - if ( shouldHideMovers() ) { - setShowMovers( false ); - } - }, debounceTimeout ); - }, - [ isFocused ] - ); + if ( ! showMovers ) { + handleOnChange( true ); + } + }; + + const debouncedHideMovers = ( event ) => { + if ( event ) { + event.stopPropagation(); + } - useEffect( () => () => clearTimeout( timeoutRef.current ), [] ); + clearTimeoutRef(); + + timeoutRef.current = setTimeout( () => { + if ( shouldHideMovers() ) { + handleOnChange( false ); + } + }, debounceTimeout ); + }; + + useEffect( () => () => clearTimeoutRef(), [] ); return { showMovers, @@ -72,13 +85,17 @@ export function useDebouncedShowMovers( { * Hook that provides a showMovers state and gesture events for DOM elements * that interact with the showMovers state. */ -export function useShowMoversGestures( { ref, debounceTimeout = 500 } ) { +export function useShowMoversGestures( { + ref, + debounceTimeout = DEBOUNCE_TIMEOUT, + onChange = noop, +} ) { const [ isFocused, setIsFocused ] = useState( false ); const { showMovers, debouncedShowMovers, debouncedHideMovers, - } = useDebouncedShowMovers( { ref, debounceTimeout, isFocused } ); + } = useDebouncedShowMovers( { ref, debounceTimeout, isFocused, onChange } ); const registerRef = useRef( false ); @@ -135,3 +152,33 @@ export function useShowMoversGestures( { ref, debounceTimeout = 500 } ) { }, }; } + +/** + * Hook that toggles the highlight (outline) state of a block + * + * @param {string} clientId The block's clientId + * + * @return {Function} Callback function to toggle highlight state. + */ +export function useToggleBlockHighlight( clientId ) { + const { toggleBlockHighlight } = useDispatch( 'core/block-editor' ); + + const updateBlockHighlight = useCallback( + ( isFocused ) => { + toggleBlockHighlight( clientId, isFocused ); + }, + [ clientId ] + ); + + useEffect( () => { + return () => { + // Sequences state change to enable editor updates (e.g. cursor + // position) to render correctly. + requestAnimationFrame( () => { + updateBlockHighlight( false ); + } ); + }; + }, [] ); + + return updateBlockHighlight; +} diff --git a/packages/block-editor/src/components/button-block-appender/index.js b/packages/block-editor/src/components/button-block-appender/index.js index 91de376e909117..385666e257e2e0 100644 --- a/packages/block-editor/src/components/button-block-appender/index.js +++ b/packages/block-editor/src/components/button-block-appender/index.js @@ -8,7 +8,7 @@ import classnames from 'classnames'; */ import { Button, Tooltip, VisuallyHidden } from '@wordpress/components'; import { _x, sprintf } from '@wordpress/i18n'; -import { Icon, plus } from '@wordpress/icons'; +import { Icon, create } from '@wordpress/icons'; /** * Internal dependencies @@ -22,6 +22,7 @@ function ButtonBlockAppender( { } ) { return ( { let label; if ( hasSingleBlockType ) { - // translators: %s: the name of the block when there is only one label = sprintf( + // translators: %s: the name of the block when there is only one _x( 'Add %s', 'directly add the only allowed block' ), blockTitle ); @@ -63,7 +64,7 @@ function ButtonBlockAppender( { label={ label } > { label } - + ); diff --git a/packages/block-editor/src/components/button-block-appender/index.native.js b/packages/block-editor/src/components/button-block-appender/index.native.js index 692c013a69f729..e879ef243a0ca8 100644 --- a/packages/block-editor/src/components/button-block-appender/index.native.js +++ b/packages/block-editor/src/components/button-block-appender/index.native.js @@ -20,6 +20,8 @@ function ButtonBlockAppender( { rootClientId, getStylesFromColorScheme, showSeparator, + isFloating = false, + onAddBlock, } ) { const appenderStyle = { ...styles.appender, @@ -30,7 +32,9 @@ function ButtonBlockAppender( { }; const addBlockButtonStyle = getStylesFromColorScheme( styles.addBlockButton, - styles.addBlockButtonDark + isFloating + ? styles.floatingAddBlockButtonDark + : styles.addBlockButtonDark ); return ( @@ -39,12 +43,17 @@ function ButtonBlockAppender( { rootClientId={ rootClientId } renderToggle={ ( { onToggle, disabled, isOpen } ) => (
); }, - migrate: colorsMigration, + migrate: oldColorsMigration, }, ]; diff --git a/packages/block-library/src/button/edit.js b/packages/block-library/src/button/edit.js index a7e33c4c3430d2..38b5b43f96d684 100644 --- a/packages/block-library/src/button/edit.js +++ b/packages/block-library/src/button/edit.js @@ -8,54 +8,26 @@ import classnames from 'classnames'; */ import { __ } from '@wordpress/i18n'; import { useCallback, useState } from '@wordpress/element'; -import { compose } from '@wordpress/compose'; import { KeyboardShortcuts, PanelBody, RangeControl, TextControl, ToggleControl, - withFallbackStyles, ToolbarButton, ToolbarGroup, Popover, } from '@wordpress/components'; import { BlockControls, - __experimentalUseGradient, - ContrastChecker, InspectorControls, - __experimentalPanelColorGradientSettings as PanelColorGradientSettings, RichText, - withColors, + __experimentalBlock as Block, __experimentalLinkControl as LinkControl, } from '@wordpress/block-editor'; import { rawShortcut, displayShortcut } from '@wordpress/keycodes'; import { link } from '@wordpress/icons'; -const { getComputedStyle } = window; - -const applyFallbackStyles = withFallbackStyles( ( node, ownProps ) => { - const { textColor, backgroundColor } = ownProps; - const backgroundColorValue = backgroundColor && backgroundColor.color; - const textColorValue = textColor && textColor.color; - //avoid the use of querySelector if textColor color is known and verify if node is available. - const textNode = - ! textColorValue && node - ? node.querySelector( '[contenteditable="true"]' ) - : null; - return { - fallbackBackgroundColor: - backgroundColorValue || ! node - ? undefined - : getComputedStyle( node ).backgroundColor, - fallbackTextColor: - textColorValue || ! textNode - ? undefined - : getComputedStyle( textNode ).color, - }; -} ); - const NEW_TAB_REL = 'noreferrer noopener'; const MIN_BORDER_RADIUS_VALUE = 0; const MAX_BORDER_RADIUS_VALUE = 50; @@ -141,18 +113,7 @@ function URLPicker( { ); } -function ButtonEdit( { - attributes, - backgroundColor, - textColor, - setBackgroundColor, - setTextColor, - fallbackBackgroundColor, - fallbackTextColor, - setAttributes, - className, - isSelected, -} ) { +function ButtonEdit( { attributes, setAttributes, className, isSelected } ) { const { borderRadius, linkTarget, @@ -186,33 +147,19 @@ function ButtonEdit( { }, [ rel, setAttributes ] ); - const { - gradientClass, - gradientValue, - setGradient, - } = __experimentalUseGradient(); return ( -
+ <> setAttributes( { text: value } ) } withoutInteractiveFormatting - className={ classnames( 'wp-block-button__link', { - 'has-background': backgroundColor.color || gradientValue, - [ backgroundColor.class ]: - ! gradientValue && backgroundColor.class, - 'has-text-color': textColor.color, - [ textColor.class ]: textColor.class, - [ gradientClass ]: gradientClass, + className={ classnames( className, 'wp-block-button__link', { 'no-border-radius': borderRadius === 0, } ) } style={ { - ...( ! backgroundColor.color && gradientValue - ? { background: gradientValue } - : { backgroundColor: backgroundColor.color } ), - color: textColor.color, borderRadius: borderRadius ? borderRadius + 'px' : undefined, @@ -226,35 +173,6 @@ function ButtonEdit( { onToggleOpenInNewTab={ onToggleOpenInNewTab } /> - - - -
+ ); } -export default compose( [ - withColors( 'backgroundColor', { textColor: 'color' } ), - applyFallbackStyles, -] )( ButtonEdit ); +export default ButtonEdit; diff --git a/packages/block-library/src/button/edit.native.js b/packages/block-library/src/button/edit.native.js index be1215a9cdbca0..6d897d1cf31fa5 100644 --- a/packages/block-library/src/button/edit.native.js +++ b/packages/block-library/src/button/edit.native.js @@ -1,7 +1,13 @@ /** * External dependencies */ -import { View, AccessibilityInfo, Platform, Clipboard } from 'react-native'; +import { + View, + AccessibilityInfo, + Platform, + Clipboard, + Text, +} from 'react-native'; /** * WordPress dependencies */ @@ -24,7 +30,7 @@ import { BottomSheet, } from '@wordpress/components'; import { Component } from '@wordpress/element'; -import { withSelect } from '@wordpress/data'; +import { withSelect, withDispatch } from '@wordpress/data'; import { isURL, prependHTTP } from '@wordpress/url'; import { link, external } from '@wordpress/icons'; @@ -52,35 +58,51 @@ class ButtonEdit extends Component { this.onChangeURL = this.onChangeURL.bind( this ); this.onClearSettings = this.onClearSettings.bind( this ); this.onLayout = this.onLayout.bind( this ); + this.onSetMaxWidth = this.onSetMaxWidth.bind( this ); + this.dismissSheet = this.dismissSheet.bind( this ); this.getURLFromClipboard = this.getURLFromClipboard.bind( this ); - this.onToggleLinkSettings = this.onToggleLinkSettings.bind( this ); + this.onShowLinkSettings = this.onShowLinkSettings.bind( this ); + this.onHideLinkSettings = this.onHideLinkSettings.bind( this ); this.onToggleButtonFocus = this.onToggleButtonFocus.bind( this ); this.setRef = this.setRef.bind( this ); + this.onRemove = this.onRemove.bind( this ); + this.getPlaceholderWidth = this.getPlaceholderWidth.bind( this ); // `isEditingURL` property is used to prevent from automatically pasting // URL from clipboard while trying to clear `Button URL` field and then // manually adding specific link this.isEditingURL = false; - const isButtonFocused = - Platform.OS === 'ios' ? ! props.hasParents : true; - this.state = { maxWidth: INITIAL_MAX_WIDTH, isLinkSheetVisible: false, - isButtonFocused, + isButtonFocused: true, + placeholderTextWidth: 0, }; } + componentDidMount() { + this.onSetMaxWidth(); + } + componentDidUpdate( prevProps, prevState ) { const { selectedId, setAttributes, editorSidebarOpened, attributes: { url }, + parentWidth, } = this.props; const { isLinkSheetVisible, isButtonFocused } = this.state; + if ( prevProps.selectedId !== selectedId ) { + this.onToggleButtonFocus( true ); + } + + if ( prevProps.parentWidth !== parentWidth ) { + this.onSetMaxWidth(); + } + if ( ( prevProps.editorSidebarOpened && ! editorSidebarOpened ) || ( prevState.isLinkSheetVisible && ! isLinkSheetVisible ) @@ -150,12 +172,25 @@ class ButtonEdit extends Component { } getBackgroundColor() { - const { backgroundColor } = this.props; - if ( backgroundColor.color ) { - // `backgroundColor` which should be set when we are able to resolve it - return backgroundColor.color; - } - return styles.fallbackButton.backgroundColor; + const { backgroundColor, attributes } = this.props; + const { style } = attributes; + + return ( + ( style && style.color && style.color.background ) || + backgroundColor.color || + styles.fallbackButton.backgroundColor + ); + } + + getTextColor() { + const { textColor, attributes } = this.props; + const { style } = attributes; + + return ( + ( style && style.color && style.color.text ) || + textColor.color || + styles.fallbackButton.color + ); } onChangeText( value ) { @@ -200,9 +235,12 @@ class ButtonEdit extends Component { } ); } - onToggleLinkSettings() { - const { isLinkSheetVisible } = this.state; - this.setState( { isLinkSheetVisible: ! isLinkSheetVisible } ); + onShowLinkSettings() { + this.setState( { isLinkSheetVisible: true } ); + } + + onHideLinkSettings() { + this.setState( { isLinkSheetVisible: false } ); } onToggleButtonFocus( value ) { @@ -223,9 +261,41 @@ class ButtonEdit extends Component { onLayout( { nativeEvent } ) { const { width } = nativeEvent.layout; - const { marginRight } = styles.button; - const buttonSpacing = 2 * marginRight; - this.setState( { maxWidth: width - buttonSpacing } ); + this.onSetMaxWidth( width ); + } + + onSetMaxWidth( width ) { + const { maxWidth } = this.state; + const { parentWidth } = this.props; + const { marginRight: spacing } = styles.button; + + const isParentWidthChanged = maxWidth !== parentWidth; + const isWidthChanged = maxWidth !== width; + + if ( parentWidth && ! width && isParentWidthChanged ) { + this.setState( { + maxWidth: parentWidth, + } ); + } else if ( ! parentWidth && width && isWidthChanged ) { + this.setState( { maxWidth: width - spacing } ); + } + } + + onRemove() { + const { numOfButtons, onDeleteBlock, onReplace } = this.props; + + if ( numOfButtons === 1 ) { + onDeleteBlock(); + } else { + onReplace( [] ); + } + } + + dismissSheet() { + this.setState( { + isLinkSheetVisible: false, + } ); + this.props.closeSettingsBottomSheet(); } getLinkSettings( url, rel, linkTarget, isCompatibleWithSettings ) { @@ -237,6 +307,7 @@ class ButtonEdit extends Component { value={ url || '' } valuePlaceholder={ __( 'Add URL' ) } onChange={ this.onChangeURL } + onSubmit={ this.dismissSheet } autoCapitalize="none" autoCorrect={ false } // eslint-disable-next-line jsx-a11y/no-autofocus @@ -263,6 +334,7 @@ class ButtonEdit extends Component { value={ rel || '' } valuePlaceholder={ __( 'None' ) } onChange={ this.onChangeLinkRel } + onSubmit={ this.dismissSheet } autoCapitalize="none" autoCorrect={ false } separatorType={ @@ -278,13 +350,39 @@ class ButtonEdit extends Component { this.richTextRef = richText; } + // Render `Text` with `placeholderText` styled as a placeholder + // to calculate its width which then is set as a `minWidth` + getPlaceholderWidth( placeholderText ) { + const { maxWidth, placeholderTextWidth } = this.state; + return ( + { + const textWidth = + nativeEvent.lines[ 0 ] && nativeEvent.lines[ 0 ].width; + if ( textWidth && textWidth !== placeholderTextWidth ) { + this.setState( { + placeholderTextWidth: Math.min( + textWidth, + maxWidth + ), + } ); + } + } } + > + { placeholderText } + + ); + } + render() { const { attributes, - textColor, isSelected, clientId, onReplace, + mergeBlocks, + parentWidth, } = this.props; const { placeholder, @@ -294,7 +392,16 @@ class ButtonEdit extends Component { linkTarget, rel, } = attributes; - const { maxWidth, isLinkSheetVisible, isButtonFocused } = this.state; + const { + maxWidth, + isLinkSheetVisible, + isButtonFocused, + placeholderTextWidth, + } = this.state; + + if ( parentWidth === 0 ) { + return null; + } const borderRadiusValue = borderRadius !== undefined @@ -313,7 +420,7 @@ class ButtonEdit extends Component { const minWidth = isButtonFocused || ( ! isButtonFocused && text && text !== '' ) ? 1 - : styles.button.minWidth; + : placeholderTextWidth; // To achieve proper expanding and shrinking `RichText` on Android, there is a need to set // a `placeholder` as an empty string when `RichText` is focused, // because `AztecView` is calculating a `minWidth` based on placeholder text. @@ -325,7 +432,8 @@ class ButtonEdit extends Component { const backgroundColor = this.getBackgroundColor(); return ( - + + { this.getPlaceholderWidth( placeholderText ) } { + this.onToggleButtonFocus( false ); + this.onSetMaxWidth(); + } } + selectionColor={ this.getTextColor() } onReplace={ onReplace } - onRemove={ () => onReplace( [] ) } + onRemove={ this.onRemove } + onMerge={ mergeBlocks } /> @@ -378,9 +490,9 @@ class ButtonEdit extends Component { @@ -389,7 +501,7 @@ class ButtonEdit extends Component { { this.getLinkSettings( url, rel, linkTarget ) } @@ -432,19 +544,29 @@ class ButtonEdit extends Component { export default compose( [ withInstanceId, withColors( 'backgroundColor', { textColor: 'color' } ), - withSelect( ( select ) => { + withSelect( ( select, { clientId } ) => { const { isEditorSidebarOpened } = select( 'core/edit-post' ); - const { getSelectedBlockClientId, getBlockParents } = select( - 'core/block-editor' - ); + const { + getSelectedBlockClientId, + getBlockCount, + getBlockRootClientId, + } = select( 'core/block-editor' ); + const parentId = getBlockRootClientId( clientId ); const selectedId = getSelectedBlockClientId(); - const hasParents = getBlockParents( selectedId ).length > 0; + const numOfButtons = getBlockCount( parentId ); return { selectedId, editorSidebarOpened: isEditorSidebarOpened(), - hasParents, + numOfButtons, + }; + } ), + withDispatch( ( dispatch ) => { + return { + closeSettingsBottomSheet() { + dispatch( 'core/edit-post' ).closeGeneralSidebar(); + }, }; } ), ] )( ButtonEdit ); diff --git a/packages/block-library/src/button/editor.native.scss b/packages/block-library/src/button/editor.native.scss index ef2e1a54b69519..47194070090401 100644 --- a/packages/block-library/src/button/editor.native.scss +++ b/packages/block-library/src/button/editor.native.scss @@ -4,6 +4,12 @@ } .outline { + // Border Width has to be spread since width is thicker + // on Android when border radius is decreased to 0 + border-left-width: $border-width; + border-right-width: $border-width; + border-top-width: $border-width; + border-bottom-width: $border-width; position: absolute; left: -($block-spacing + $border-width); right: -($block-spacing + $border-width); @@ -25,11 +31,12 @@ padding: $block-spacing; max-width: 580px; min-width: 108px; - margin: $panel-padding; + margin: 2 * $panel-padding; } .fallbackButton { background-color: $button-fallback-bg; + color: $white; } .clearLinkButton { @@ -39,3 +46,10 @@ .placeholderTextColor { color: rgba($color: $white, $alpha: 0.43); } + +.placeholder { + font-family: $default-regular-font; + min-height: 22px; + font-size: 16px; + display: none; +} diff --git a/packages/block-library/src/button/editor.scss b/packages/block-library/src/button/editor.scss index db005f644042ce..efed2d4910b1a1 100644 --- a/packages/block-library/src/button/editor.scss +++ b/packages/block-library/src/button/editor.scss @@ -13,10 +13,7 @@ .wp-block-button { position: relative; - - [contenteditable] { - cursor: text; - } + cursor: text; // Make placeholder text white unless custom colors or outline versions are chosen. &:not(.has-text-color):not(.is-style-outline) [data-rich-text-placeholder]::after { @@ -24,7 +21,7 @@ } // Add outline to button on focus to indicate focus-state - .block-editor-rich-text__editable:focus { + &:focus { box-shadow: 0 0 0 1px $white, 0 0 0 3px $blue-medium-500; // Windows' High Contrast mode will show this outline, but not the box-shadow. @@ -33,7 +30,7 @@ } // Increase placeholder opacity to meet contrast ratios. - [data-rich-text-placeholder]::after { + &[data-rich-text-placeholder]::after { opacity: 0.8; } } diff --git a/packages/block-library/src/button/index.js b/packages/block-library/src/button/index.js index f71e2187de083f..fab563649938fb 100644 --- a/packages/block-library/src/button/index.js +++ b/packages/block-library/src/button/index.js @@ -34,6 +34,8 @@ export const settings = { align: true, alignWide: false, reusable: false, + lightBlockWrapper: true, + __experimentalColor: { gradients: true }, }, parent: [ 'core/buttons' ], styles: [ diff --git a/packages/block-library/src/button/index.native.js b/packages/block-library/src/button/index.native.js deleted file mode 100644 index b3a3b7c131dfe1..00000000000000 --- a/packages/block-library/src/button/index.native.js +++ /dev/null @@ -1,11 +0,0 @@ -/** - * Internal dependencies - */ -import { settings as webSettings } from './index.js'; - -export { metadata, name } from './index.js'; - -export const settings = { - ...webSettings, - parent: undefined, -}; diff --git a/packages/block-library/src/button/save.js b/packages/block-library/src/button/save.js index 542222f49e98c2..6a7aeb8088c1a7 100644 --- a/packages/block-library/src/button/save.js +++ b/packages/block-library/src/button/save.js @@ -6,54 +6,16 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import { - RichText, - getColorClassName, - __experimentalGetGradientClass, -} from '@wordpress/block-editor'; +import { RichText } from '@wordpress/block-editor'; export default function save( { attributes } ) { - const { - backgroundColor, - borderRadius, - customBackgroundColor, - customTextColor, - customGradient, - linkTarget, - gradient, - rel, - text, - textColor, - title, - url, - } = attributes; - - const textClass = getColorClassName( 'color', textColor ); - const backgroundClass = - ! customGradient && - getColorClassName( 'background-color', backgroundColor ); - const gradientClass = __experimentalGetGradientClass( gradient ); + const { borderRadius, linkTarget, rel, text, title, url } = attributes; const buttonClasses = classnames( 'wp-block-button__link', { - 'has-text-color': textColor || customTextColor, - [ textClass ]: textClass, - 'has-background': - backgroundColor || - customBackgroundColor || - customGradient || - gradient, - [ backgroundClass ]: backgroundClass, 'no-border-radius': borderRadius === 0, - [ gradientClass ]: gradientClass, } ); const buttonStyle = { - background: customGradient ? customGradient : undefined, - backgroundColor: - backgroundClass || customGradient || gradient - ? undefined - : customBackgroundColor, - color: textClass ? undefined : customTextColor, borderRadius: borderRadius ? borderRadius + 'px' : undefined, }; @@ -62,17 +24,15 @@ export default function save( { attributes } ) { // A title will no longer be assigned for new or updated button block links. return ( -
- -
+ ); } diff --git a/packages/block-library/src/button/style.scss b/packages/block-library/src/button/style.scss index 7bbe8900b8dc29..40f44b71ace52b 100644 --- a/packages/block-library/src/button/style.scss +++ b/packages/block-library/src/button/style.scss @@ -1,24 +1,13 @@ $blocks-button__height: 56px; -.wp-block-button { - color: $white; - - &.aligncenter { - text-align: center; - } - - &.alignright { - /*rtl:ignore*/ - text-align: right; - } -} - +// Prefer the link selector instead of the regular button classname +// to support the previous markup in addition to the new one. .wp-block-button__link { + color: $white; background-color: $dark-gray-700; border: none; border-radius: $blocks-button__height / 2; box-shadow: none; - color: inherit; cursor: pointer; display: inline-block; font-size: $big-font-size; @@ -32,26 +21,36 @@ $blocks-button__height: 56px; &:focus, &:active, &:visited { - color: inherit; + color: $white; } -} -.wp-gs .wp-block-button__link:not(.has-background) { - background-color: var(--wp--color--primary); + &.aligncenter { + text-align: center; + } + + &.alignright { + /*rtl:ignore*/ + text-align: right; + } } -.is-style-squared .wp-block-button__link { +// the first selector is required for old buttons markup +.wp-block-button.is-style-squared, +.wp-block-button__link.wp-block-button.is-style-squared { border-radius: 0; } -.no-border-radius.wp-block-button__link { + + +// the first selector is required for old buttons markup + +.wp-block-button.no-border-radius, +.wp-block-button__link.wp-block-button.no-border-radius { border-radius: 0 !important; } -.is-style-outline { +.wp-block-button.is-style-outline, +.wp-block-button__link.is-style-outline { color: $dark-gray-700; - - .wp-block-button__link { - background-color: transparent; - border: 2px solid; - } + background-color: transparent; + border: 2px solid; } diff --git a/packages/block-library/src/buttons/edit.js b/packages/block-library/src/buttons/edit.js index 15590ca49e713b..d9b76ed8f1bcb6 100644 --- a/packages/block-library/src/buttons/edit.js +++ b/packages/block-library/src/buttons/edit.js @@ -13,9 +13,6 @@ import { name as buttonBlockName } from '../button/'; const ALLOWED_BLOCKS = [ buttonBlockName ]; const BUTTONS_TEMPLATE = [ [ 'core/button' ] ]; -const UI_PARTS = { - hasSelectedUI: false, -}; // Inside buttons block alignment options are not supported. const alignmentHooksSetting = { @@ -29,7 +26,6 @@ function ButtonsEdit( { className } ) { diff --git a/packages/block-library/src/buttons/edit.native.js b/packages/block-library/src/buttons/edit.native.js new file mode 100644 index 00000000000000..c80c844afd41e6 --- /dev/null +++ b/packages/block-library/src/buttons/edit.native.js @@ -0,0 +1,142 @@ +/** + * External dependencies + */ +import { View } from 'react-native'; +/** + * WordPress dependencies + */ +import { + InnerBlocks, + __experimentalAlignmentHookSettingsProvider as AlignmentHookSettingsProvider, +} from '@wordpress/block-editor'; +import { withSelect, withDispatch } from '@wordpress/data'; +import { compose, useResizeObserver } from '@wordpress/compose'; +import { createBlock } from '@wordpress/blocks'; +import { useState, useEffect } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import { name as buttonBlockName } from '../button/'; +import styles from './editor.scss'; + +const ALLOWED_BLOCKS = [ buttonBlockName ]; +const BUTTONS_TEMPLATE = [ [ 'core/button' ] ]; + +function ButtonsEdit( { + isSelected, + attributes, + onDelete, + onAddNextButton, + shouldDelete, + isInnerButtonSelected, +} ) { + const { align } = attributes; + const [ resizeObserver, sizes ] = useResizeObserver(); + const [ maxWidth, setMaxWidth ] = useState( 0 ); + const shouldRenderFooterAppender = isSelected || isInnerButtonSelected; + const { marginLeft: spacing } = styles.spacing; + + useEffect( () => { + const margins = 2 * styles.parent.marginRight; + const { width } = sizes || {}; + if ( width ) { + setMaxWidth( width - margins ); + } + }, [ sizes ] ); + + function renderFooterAppender() { + return ( + + + + ); + } + + // Inside buttons block alignment options are not supported. + const alignmentHooksSetting = { + isEmbedButton: true, + }; + + return ( + + { resizeObserver } + + + ); +} + +export default compose( + withSelect( ( select, { clientId } ) => { + const { + getBlockCount, + getBlockParents, + getSelectedBlockClientId, + } = select( 'core/block-editor' ); + const selectedBlockClientId = getSelectedBlockClientId(); + const selectedBlockParents = getBlockParents( + selectedBlockClientId, + true + ); + + return { + // The purpose of `shouldDelete` check is giving the ability to pass to + // mobile toolbar function called `onDelete` which removes the whole + // `Buttons` container along with the last inner button when + // there is exactly one button. + shouldDelete: getBlockCount( clientId ) === 1, + isInnerButtonSelected: selectedBlockParents[ 0 ] === clientId, + }; + } ), + withDispatch( ( dispatch, { clientId }, registry ) => { + const { replaceInnerBlocks, selectBlock, removeBlock } = dispatch( + 'core/block-editor' + ); + const { getBlocks, getBlockOrder } = registry.select( + 'core/block-editor' + ); + const innerBlocks = getBlocks( clientId ); + + return { + // The purpose of `onAddNextButton` is giving the ability to automatically + // adding `Button` inside `Buttons` block on the appender press event. + onAddNextButton: ( selectedId ) => { + const order = getBlockOrder( clientId ); + const selectedButtonIndex = order.findIndex( + ( i ) => i === selectedId + ); + + const index = + selectedButtonIndex === -1 + ? order.length + 1 + : selectedButtonIndex; + + const insertedBlock = createBlock( 'core/button' ); + + innerBlocks.splice( index + 1, 0, insertedBlock ); + + replaceInnerBlocks( clientId, innerBlocks, true ); + selectBlock( insertedBlock.clientId ); + }, + onDelete: () => { + removeBlock( clientId ); + }, + }; + } ) +)( ButtonsEdit ); diff --git a/packages/block-library/src/buttons/editor.native.scss b/packages/block-library/src/buttons/editor.native.scss new file mode 100644 index 00000000000000..f4816da8494d41 --- /dev/null +++ b/packages/block-library/src/buttons/editor.native.scss @@ -0,0 +1,12 @@ +.parent { + margin: $block-edge-to-content; +} + +.appenderContainer { + flex: 1; + margin: $block-selected-margin; +} + +.spacing { + margin: 2 * $block-selected-margin; +} diff --git a/packages/block-library/src/buttons/style.scss b/packages/block-library/src/buttons/style.scss index f82a5191316863..3d4843d5ca3e9b 100644 --- a/packages/block-library/src/buttons/style.scss +++ b/packages/block-library/src/buttons/style.scss @@ -1,7 +1,15 @@ -.wp-block-buttons .wp-block-button { +// Increased specificity to override blocks default margin. +.wp-block-buttons .wp-block-button.wp-block-button { display: inline-block; - margin: $grid-unit-05; + margin-right: $grid-unit-10; + margin-bottom: $grid-unit-10; } + +.wp-block-buttons.alignright .wp-block-button { + margin-right: none; + margin-left: $grid-unit-10; +} + .wp-block-buttons.aligncenter { text-align: center; } diff --git a/packages/block-library/src/categories/index.js b/packages/block-library/src/categories/index.js index 42b863d5c87458..e7b8d9310e75cd 100644 --- a/packages/block-library/src/categories/index.js +++ b/packages/block-library/src/categories/index.js @@ -20,5 +20,6 @@ export const settings = { align: true, html: false, }, + example: {}, edit, }; diff --git a/packages/block-library/src/code/edit.js b/packages/block-library/src/code/edit.js index 5aa4b337bd3f12..03ebb86b4ec71a 100644 --- a/packages/block-library/src/code/edit.js +++ b/packages/block-library/src/code/edit.js @@ -6,17 +6,22 @@ import { __ } from '@wordpress/i18n'; /** * Internal dependencies */ -import { PlainText } from '@wordpress/block-editor'; +import { + PlainText, + __experimentalBlock as Block, +} from '@wordpress/block-editor'; -export default function CodeEdit( { attributes, setAttributes, className } ) { +export default function CodeEdit( { attributes, setAttributes } ) { return ( -
+ setAttributes( { content } ) } placeholder={ __( 'Write code…' ) } aria-label={ __( 'Code' ) } /> - </div> + </Block.pre> ); } diff --git a/packages/block-library/src/code/editor.scss b/packages/block-library/src/code/editor.scss index 5a4d5ee76e1acc..bc47a4f35ee9da 100644 --- a/packages/block-library/src/code/editor.scss +++ b/packages/block-library/src/code/editor.scss @@ -1,14 +1,4 @@ -.wp-block-code .block-editor-plain-text { - font-family: $editor-html-font; - color: $dark-gray-800; - - /* Fonts smaller than 16px causes mobile safari to zoom. */ - font-size: $mobile-text-min-font-size; - @include break-small { - font-size: $default-font-size; - } - - &:focus { - box-shadow: none; - } +.wp-block-code > code { + // PlainText cannot be an inline element yet. + display: block; } diff --git a/packages/block-library/src/code/index.js b/packages/block-library/src/code/index.js index 65506cfcdfc5d7..ce07ea4e3e98ad 100644 --- a/packages/block-library/src/code/index.js +++ b/packages/block-library/src/code/index.js @@ -24,14 +24,17 @@ export const settings = { icon, example: { attributes: { + /* eslint-disable @wordpress/i18n-no-collapsible-whitespace */ // translators: Preserve \n markers for line breaks content: __( '// A "block" is the abstract term used\n// to describe units of markup that\n// when composed together, form the\n// content or layout of a page.\nregisterBlockType( name, settings );' ), + /* eslint-enable @wordpress/i18n-no-collapsible-whitespace */ }, }, supports: { html: false, + lightBlockWrapper: true, }, transforms, edit, diff --git a/packages/block-library/src/column/edit.js b/packages/block-library/src/column/edit.js index 1760c0da4b75d4..1664bff4ffeb59 100644 --- a/packages/block-library/src/column/edit.js +++ b/packages/block-library/src/column/edit.js @@ -63,7 +63,7 @@ function ColumnEdit( { templateLock={ false } renderAppender={ hasChildBlocks - ? false + ? undefined : () => <InnerBlocks.ButtonBlockAppender /> } __experimentalTagName={ Block.div } diff --git a/packages/block-library/src/column/edit.native.js b/packages/block-library/src/column/edit.native.js new file mode 100644 index 00000000000000..70d519ca2e78c6 --- /dev/null +++ b/packages/block-library/src/column/edit.native.js @@ -0,0 +1,118 @@ +/** + * External dependencies + */ +import { View } from 'react-native'; + +/** + * WordPress dependencies + */ +import { withSelect } from '@wordpress/data'; +import { compose, withPreferredColorScheme } from '@wordpress/compose'; +import { + InnerBlocks, + BlockControls, + BlockVerticalAlignmentToolbar, +} from '@wordpress/block-editor'; +/** + * Internal dependencies + */ +import styles from './editor.scss'; + +function ColumnEdit( { + attributes, + setAttributes, + hasChildren, + isSelected, + getStylesFromColorScheme, + isParentSelected, + contentStyle, +} ) { + const { verticalAlignment } = attributes; + + const updateAlignment = ( alignment ) => { + setAttributes( { verticalAlignment: alignment } ); + }; + + if ( ! isSelected && ! hasChildren ) { + return ( + <View + style={ [ + ! isParentSelected && + getStylesFromColorScheme( + styles.columnPlaceholder, + styles.columnPlaceholderDark + ), + contentStyle, + styles.columnPlaceholderNotSelected, + ] } + ></View> + ); + } + + return ( + <> + <BlockControls> + <BlockVerticalAlignmentToolbar + onChange={ updateAlignment } + value={ verticalAlignment } + /> + </BlockControls> + <View + style={ [ + contentStyle, + isSelected && hasChildren && styles.innerBlocksBottomSpace, + ] } + > + <InnerBlocks + renderAppender={ + isSelected && InnerBlocks.ButtonBlockAppender + } + /> + </View> + </> + ); +} + +function ColumnEditWrapper( props ) { + const { verticalAlignment } = props.attributes; + + const getVerticalAlignmentRemap = ( alignment ) => { + if ( ! alignment ) return styles.flexBase; + return { + ...styles.flexBase, + ...styles[ `is-vertically-aligned-${ alignment }` ], + }; + }; + + return ( + <View style={ getVerticalAlignmentRemap( verticalAlignment ) }> + <ColumnEdit { ...props } /> + </View> + ); +} + +export default compose( [ + withSelect( ( select, { clientId } ) => { + const { + getBlockCount, + getBlockRootClientId, + getSelectedBlockClientId, + } = select( 'core/block-editor' ); + + const selectedBlockClientId = getSelectedBlockClientId(); + const isSelected = selectedBlockClientId === clientId; + + const parentId = getBlockRootClientId( clientId ); + const hasChildren = !! getBlockCount( clientId ); + + const isParentSelected = + selectedBlockClientId && selectedBlockClientId === parentId; + + return { + hasChildren, + isParentSelected, + isSelected, + }; + } ), + withPreferredColorScheme, +] )( ColumnEditWrapper ); diff --git a/packages/block-library/src/column/editor.native.scss b/packages/block-library/src/column/editor.native.scss new file mode 100644 index 00000000000000..ec9579c63234b1 --- /dev/null +++ b/packages/block-library/src/column/editor.native.scss @@ -0,0 +1,36 @@ +.columnPlaceholderNotSelected { + padding-top: $block-selected-to-content; +} + +.columnPlaceholder { + flex: 1; + padding: $block-selected-to-content; + background-color: $white; + border: $border-width dashed $gray; + border-radius: 4px; +} + +.columnPlaceholderDark { + background-color: $black; + border: $border-width dashed $gray-70; +} + +.innerBlocksBottomSpace { + margin-bottom: $block-selected-to-content; +} + +.is-vertically-aligned-top { + justify-content: flex-start; +} + +.is-vertically-aligned-center { + justify-content: center; +} + +.is-vertically-aligned-bottom { + justify-content: flex-end; +} + +.flexBase { + flex: 1; +} diff --git a/packages/block-library/src/column/index.native.js b/packages/block-library/src/column/index.native.js new file mode 100644 index 00000000000000..d03c4756174bcc --- /dev/null +++ b/packages/block-library/src/column/index.native.js @@ -0,0 +1,17 @@ +/** + * Internal dependencies + */ +import * as webSettings from './index.js'; +import metadata from './block.json'; + +const { name } = metadata; + +export { metadata, name }; + +export const settings = { + ...webSettings.settings, + supports: { + ...webSettings.settings.supports, + inserter: true, + }, +}; diff --git a/packages/block-library/src/columns/block.json b/packages/block-library/src/columns/block.json index 8dc01cfafab4dd..3c22ca71fba621 100644 --- a/packages/block-library/src/columns/block.json +++ b/packages/block-library/src/columns/block.json @@ -4,18 +4,6 @@ "attributes": { "verticalAlignment": { "type": "string" - }, - "backgroundColor": { - "type": "string" - }, - "customBackgroundColor": { - "type": "string" - }, - "customTextColor" : { - "type": "string" - }, - "textColor": { - "type": "string" } } } diff --git a/packages/block-library/src/columns/deprecated.js b/packages/block-library/src/columns/deprecated.js index 3d08e3d74c2183..34b3076904a63f 100644 --- a/packages/block-library/src/columns/deprecated.js +++ b/packages/block-library/src/columns/deprecated.js @@ -8,7 +8,7 @@ import classnames from 'classnames'; * WordPress dependencies */ import { createBlock } from '@wordpress/blocks'; -import { InnerBlocks } from '@wordpress/block-editor'; +import { InnerBlocks, getColorClassName } from '@wordpress/block-editor'; /** * Given an HTML string for a deprecated columns inner block, returns the @@ -38,7 +38,84 @@ function getDeprecatedLayoutColumn( originalContent ) { } } +const migrateCustomColors = ( attributes ) => { + if ( ! attributes.customTextColor && ! attributes.customBackgroundColor ) { + return attributes; + } + const style = { color: {} }; + if ( attributes.customTextColor ) { + style.color.text = attributes.customTextColor; + } + if ( attributes.customBackgroundColor ) { + style.color.background = attributes.customBackgroundColor; + } + return { + ...omit( attributes, [ 'customTextColor', 'customBackgroundColor' ] ), + style, + }; +}; + export default [ + { + attributes: { + verticalAlignment: { + type: 'string', + }, + backgroundColor: { + type: 'string', + }, + customBackgroundColor: { + type: 'string', + }, + customTextColor: { + type: 'string', + }, + textColor: { + type: 'string', + }, + }, + migrate: migrateCustomColors, + save( { attributes } ) { + const { + verticalAlignment, + backgroundColor, + customBackgroundColor, + textColor, + customTextColor, + } = attributes; + + const backgroundClass = getColorClassName( + 'background-color', + backgroundColor + ); + + const textClass = getColorClassName( 'color', textColor ); + + const className = classnames( { + 'has-background': backgroundColor || customBackgroundColor, + 'has-text-color': textColor || customTextColor, + [ backgroundClass ]: backgroundClass, + [ textClass ]: textClass, + [ `are-vertically-aligned-${ verticalAlignment }` ]: verticalAlignment, + } ); + + const style = { + backgroundColor: backgroundClass + ? undefined + : customBackgroundColor, + color: textClass ? undefined : customTextColor, + }; + + return ( + <div + className={ className ? className : undefined } + style={ style } + > + <InnerBlocks.Content /> + </div> + ); + }, + }, { attributes: { columns: { diff --git a/packages/block-library/src/columns/edit.js b/packages/block-library/src/columns/edit.js index 05aaed154a4e4d..372e535a931a8f 100644 --- a/packages/block-library/src/columns/edit.js +++ b/packages/block-library/src/columns/edit.js @@ -9,7 +9,6 @@ import { dropRight, get, map, times } from 'lodash'; */ import { __ } from '@wordpress/i18n'; import { PanelBody, RangeControl } from '@wordpress/components'; -import { useRef } from '@wordpress/element'; import { InspectorControls, @@ -17,7 +16,6 @@ import { BlockControls, BlockVerticalAlignmentToolbar, __experimentalBlockVariationPicker, - __experimentalUseColors, __experimentalBlock as Block, } from '@wordpress/block-editor'; import { withDispatch, useDispatch, useSelect } from '@wordpress/data'; @@ -61,22 +59,6 @@ function ColumnsEditContainer( { [ clientId ] ); - const ref = useRef(); - const { - BackgroundColor, - InspectorControlsColorPanel, - TextColor, - } = __experimentalUseColors( - [ - { name: 'textColor', property: 'color' }, - { name: 'backgroundColor', className: 'has-background' }, - ], - { - contrastCheckers: [ { backgroundColor: true, textColor: true } ], - colorDetector: { targetRef: ref }, - } - ); - const classes = classnames( { [ `are-vertically-aligned-${ verticalAlignment }` ]: verticalAlignment, } ); @@ -100,32 +82,14 @@ function ColumnsEditContainer( { /> </PanelBody> </InspectorControls> - { InspectorControlsColorPanel } - <BackgroundColor> - { ( backgroundProps ) => ( - <TextColor> - { ( textColorProps ) => ( - <InnerBlocks - allowedBlocks={ ALLOWED_BLOCKS } - __experimentalMoverDirection="horizontal" - ref={ ref } - __experimentalTagName={ Block.div } - __experimentalPassedProps={ { - className: classnames( - classes, - backgroundProps.className, - textColorProps.className - ), - style: { - ...backgroundProps.style, - ...textColorProps.style, - }, - } } - /> - ) } - </TextColor> - ) } - </BackgroundColor> + <InnerBlocks + allowedBlocks={ ALLOWED_BLOCKS } + __experimentalMoverDirection="horizontal" + __experimentalTagName={ Block.div } + __experimentalPassedProps={ { + className: classes, + } } + /> </> ); } diff --git a/packages/block-library/src/columns/edit.native.js b/packages/block-library/src/columns/edit.native.js new file mode 100644 index 00000000000000..a3394d02ed9657 --- /dev/null +++ b/packages/block-library/src/columns/edit.native.js @@ -0,0 +1,280 @@ +/** + * External dependencies + */ +import { View } from 'react-native'; +import { dropRight, times } from 'lodash'; + +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +import { PanelBody, RangeControl } from '@wordpress/components'; +import { + InspectorControls, + InnerBlocks, + BlockControls, + BlockVerticalAlignmentToolbar, +} from '@wordpress/block-editor'; +import { withDispatch, useSelect } from '@wordpress/data'; +import { useEffect, useState } from '@wordpress/element'; +import { useResizeObserver } from '@wordpress/compose'; +import { createBlock } from '@wordpress/blocks'; +/** + * Internal dependencies + */ +import styles from './editor.scss'; + +/** + * Allowed blocks constant is passed to InnerBlocks precisely as specified here. + * The contents of the array should never change. + * The array should contain the name of each block that is allowed. + * In columns block, the only block we allow is 'core/column'. + * + * @constant + * @type {string[]} + */ +const ALLOWED_BLOCKS = [ 'core/column' ]; + +/** + * Number of columns to assume for template in case the user opts to skip + * template option selection. + * + * @type {number} + */ +const DEFAULT_COLUMNS = 2; +const MIN_COLUMNS_NUMBER = 1; + +const BREAKPOINTS = { + mobile: 480, + large: 768, +}; + +function ColumnsEditContainer( { + attributes, + updateAlignment, + updateColumns, + columnCount, + isSelected, + onAddNextColumn, + onDeleteBlock, +} ) { + const [ resizeListener, sizes ] = useResizeObserver(); + const [ columnsInRow, setColumnsInRow ] = useState( MIN_COLUMNS_NUMBER ); + + const containerMaxWidth = styles.columnsContainer.maxWidth; + + const { verticalAlignment } = attributes; + const { width } = sizes || {}; + + useEffect( () => { + const newColumnCount = ! columnCount ? DEFAULT_COLUMNS : columnCount; + updateColumns( columnCount, newColumnCount ); + setColumnsInRow( getColumnsInRow( width, newColumnCount ) ); + }, [ columnCount ] ); + + useEffect( () => { + setColumnsInRow( getColumnsInRow( width, columnCount ) ); + }, [ width ] ); + + const getColumnWidth = ( containerWidth = containerMaxWidth ) => { + const minWidth = Math.min( containerWidth, containerMaxWidth ); + const columnBaseWidth = minWidth / columnsInRow; + + let columnWidth = columnBaseWidth; + if ( columnsInRow > 1 ) { + const margins = columnsInRow * 2 * styles.columnMargin.marginLeft; + columnWidth = ( minWidth - margins ) / columnsInRow; + } + + return columnWidth; + }; + + const getColumnsInRow = ( containerWidth, columnsNumber ) => { + if ( containerWidth < BREAKPOINTS.mobile ) { + // show only 1 Column in row for mobile breakpoint container width + return 1; + } else if ( containerWidth < BREAKPOINTS.large ) { + // show 2 Column in row for large breakpoint container width + return Math.min( Math.max( 1, columnCount ), 2 ); + } + // show all Column in one row + return Math.max( 1, columnsNumber ); + }; + + const renderAppender = () => { + if ( isSelected ) { + return ( + <InnerBlocks.ButtonBlockAppender + onAddBlock={ onAddNextColumn } + /> + ); + } + return null; + }; + + return ( + <> + <InspectorControls> + <PanelBody title={ __( 'Columns Settings' ) }> + <RangeControl + label={ __( 'Number of columns' ) } + icon="columns" + value={ columnCount } + onChange={ ( value ) => + updateColumns( columnCount, value ) + } + min={ MIN_COLUMNS_NUMBER } + max={ columnCount + 1 } + separatorType={ 'none' } + type="stepper" + /> + </PanelBody> + </InspectorControls> + <BlockControls> + <BlockVerticalAlignmentToolbar + onChange={ updateAlignment } + value={ verticalAlignment } + /> + </BlockControls> + <View style={ isSelected && styles.innerBlocksSelected }> + { resizeListener } + <InnerBlocks + renderAppender={ renderAppender } + __experimentalMoverDirection={ + columnsInRow > 1 ? 'horizontal' : undefined + } + horizontal={ true } + allowedBlocks={ ALLOWED_BLOCKS } + contentResizeMode="stretch" + onAddBlock={ onAddNextColumn } + onDeleteBlock={ + columnCount === 1 ? onDeleteBlock : undefined + } + contentStyle={ { width: getColumnWidth( width ) } } + /> + </View> + </> + ); +} + +const ColumnsEditContainerWrapper = withDispatch( + ( dispatch, ownProps, registry ) => ( { + /** + * Update all child Column blocks with a new vertical alignment setting + * based on whatever alignment is passed in. This allows change to parent + * to overide anything set on a individual column basis. + * + * @param {string} verticalAlignment the vertical alignment setting + */ + updateAlignment( verticalAlignment ) { + const { clientId, setAttributes } = ownProps; + const { updateBlockAttributes } = dispatch( 'core/block-editor' ); + const { getBlockOrder } = registry.select( 'core/block-editor' ); + + // Update own alignment. + setAttributes( { verticalAlignment } ); + + // Update all child Column Blocks to match + const innerBlockClientIds = getBlockOrder( clientId ); + innerBlockClientIds.forEach( ( innerBlockClientId ) => { + updateBlockAttributes( innerBlockClientId, { + verticalAlignment, + } ); + } ); + }, + updateBlockSettings( settings ) { + const { clientId } = ownProps; + const { updateBlockListSettings } = dispatch( 'core/block-editor' ); + updateBlockListSettings( clientId, settings ); + }, + /** + * Updates the column columnCount, including necessary revisions to child Column + * blocks to grant required or redistribute available space. + * + * @param {number} previousColumns Previous column columnCount. + * @param {number} newColumns New column columnCount. + */ + updateColumns( previousColumns, newColumns ) { + const { clientId } = ownProps; + const { replaceInnerBlocks } = dispatch( 'core/block-editor' ); + const { getBlocks, getBlockAttributes } = registry.select( + 'core/block-editor' + ); + + let innerBlocks = getBlocks( clientId ); + + // Redistribute available width for existing inner blocks. + const isAddingColumn = newColumns > previousColumns; + + if ( isAddingColumn ) { + // Get verticalAlignment from Columns block to set the same to new Column + const { verticalAlignment } = getBlockAttributes( clientId ); + + innerBlocks = [ + ...innerBlocks, + ...times( newColumns - previousColumns, () => { + return createBlock( 'core/column', { + verticalAlignment, + } ); + } ), + ]; + } else { + // The removed column will be the last of the inner blocks. + innerBlocks = dropRight( + innerBlocks, + previousColumns - newColumns + ); + } + + replaceInnerBlocks( clientId, innerBlocks, false ); + }, + onAddNextColumn: () => { + const { clientId } = ownProps; + const { replaceInnerBlocks, selectBlock } = dispatch( + 'core/block-editor' + ); + const { getBlocks, getBlockAttributes } = registry.select( + 'core/block-editor' + ); + + // Get verticalAlignment from Columns block to set the same to new Column + const { verticalAlignment } = getBlockAttributes( clientId ); + + const innerBlocks = getBlocks( clientId ); + + const insertedBlock = createBlock( 'core/column', { + verticalAlignment, + } ); + + innerBlocks.push( insertedBlock ); + + replaceInnerBlocks( clientId, innerBlocks, true ); + selectBlock( insertedBlock.clientId ); + }, + onDeleteBlock: () => { + const { clientId } = ownProps; + const { removeBlock } = dispatch( 'core/block-editor' ); + removeBlock( clientId ); + }, + } ) +)( ColumnsEditContainer ); + +const ColumnsEdit = ( props ) => { + const { clientId } = props; + const { columnCount } = useSelect( + ( select ) => { + const { getBlockCount } = select( 'core/block-editor' ); + + return { + columnCount: getBlockCount( clientId ), + }; + }, + [ clientId ] + ); + + return ( + <ColumnsEditContainerWrapper columnCount={ columnCount } { ...props } /> + ); +}; + +export default ColumnsEdit; diff --git a/packages/block-library/src/columns/editor.native.scss b/packages/block-library/src/columns/editor.native.scss new file mode 100644 index 00000000000000..991655a13f3278 --- /dev/null +++ b/packages/block-library/src/columns/editor.native.scss @@ -0,0 +1,11 @@ +.columnsContainer { + max-width: $content-width; +} + +.innerBlocksSelected { + margin-bottom: $block-edge-to-content; +} + +.columnMargin { + margin: $block-edge-to-content / 2; +} diff --git a/packages/block-library/src/columns/editor.scss b/packages/block-library/src/columns/editor.scss index 73231a940dd83c..d4928ac611d83a 100644 --- a/packages/block-library/src/columns/editor.scss +++ b/packages/block-library/src/columns/editor.scss @@ -4,14 +4,6 @@ max-width: none; } -// Ideally this shouldn't be necessary. There should be no default margins in -// the editor. -.editor-styles-wrapper .block-editor-block-list__block.wp-block-column, -.editor-styles-wrapper .block-editor-block-list__block.wp-block-columns { - margin-top: 0; - margin-bottom: 0; -} - // To do: remove horizontal margin override by the editor. @include break-small() { .editor-styles-wrapper diff --git a/packages/block-library/src/columns/index.js b/packages/block-library/src/columns/index.js index 8d94dcd82ea4ec..dec1d8672e6974 100644 --- a/packages/block-library/src/columns/index.js +++ b/packages/block-library/src/columns/index.js @@ -27,6 +27,7 @@ export const settings = { align: [ 'wide', 'full' ], html: false, lightBlockWrapper: true, + __experimentalColor: { gradients: true }, }, variations, example: { diff --git a/packages/block-library/src/columns/save.js b/packages/block-library/src/columns/save.js index 3d2249389910d2..0d9a5305cbeaeb 100644 --- a/packages/block-library/src/columns/save.js +++ b/packages/block-library/src/columns/save.js @@ -6,39 +6,17 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import { InnerBlocks, getColorClassName } from '@wordpress/block-editor'; +import { InnerBlocks } from '@wordpress/block-editor'; export default function save( { attributes } ) { - const { - verticalAlignment, - backgroundColor, - customBackgroundColor, - textColor, - customTextColor, - } = attributes; - - const backgroundClass = getColorClassName( - 'background-color', - backgroundColor - ); - - const textClass = getColorClassName( 'color', textColor ); + const { verticalAlignment } = attributes; const className = classnames( { - 'has-background': backgroundColor || customBackgroundColor, - 'has-text-color': textColor || customTextColor, - [ backgroundClass ]: backgroundClass, - [ textClass ]: textClass, [ `are-vertically-aligned-${ verticalAlignment }` ]: verticalAlignment, } ); - const style = { - backgroundColor: backgroundClass ? undefined : customBackgroundColor, - color: textClass ? undefined : customTextColor, - }; - return ( - <div className={ className ? className : undefined } style={ style }> + <div className={ className ? className : undefined }> <InnerBlocks.Content /> </div> ); diff --git a/packages/block-library/src/cover/block.json b/packages/block-library/src/cover/block.json index cb6a0a1c330e64..c2b3098b16c23e 100644 --- a/packages/block-library/src/cover/block.json +++ b/packages/block-library/src/cover/block.json @@ -32,6 +32,9 @@ "minHeight": { "type": "number" }, + "minHeightUnit": { + "type": "string" + }, "gradient": { "type": "string" }, diff --git a/packages/block-library/src/cover/edit.js b/packages/block-library/src/cover/edit.js index b9354dc6fc7363..5fe5db7a206757 100644 --- a/packages/block-library/src/cover/edit.js +++ b/packages/block-library/src/cover/edit.js @@ -20,7 +20,7 @@ import { ToggleControl, withNotices, } from '@wordpress/components'; -import { compose, withInstanceId } from '@wordpress/compose'; +import { compose, withInstanceId, useInstanceId } from '@wordpress/compose'; import { BlockControls, BlockIcon, @@ -32,6 +32,7 @@ import { ColorPalette, __experimentalUseGradient, __experimentalPanelColorGradientSettings as PanelColorGradientSettings, + __experimentalUnitControl as UnitControl, } from '@wordpress/block-editor'; import { __ } from '@wordpress/i18n'; import { withDispatch } from '@wordpress/data'; @@ -45,6 +46,7 @@ import { IMAGE_BACKGROUND_TYPE, VIDEO_BACKGROUND_TYPE, COVER_MIN_HEIGHT, + CSS_UNITS, backgroundImageStyles, dimRatioToClass, } from './shared'; @@ -71,47 +73,57 @@ function retrieveFastAverageColor() { return retrieveFastAverageColor.fastAverageColor; } -const CoverHeightInput = withInstanceId( function( { - value = '', - instanceId, +function CoverHeightInput( { onChange, + onUnitChange, + unit = 'px', + value = '', } ) { const [ temporaryInput, setTemporaryInput ] = useState( null ); + const instanceId = useInstanceId( UnitControl ); const inputId = `block-cover-height-input-${ instanceId }`; + const isPx = unit === 'px'; + + const handleOnChange = ( unprocessedValue ) => { + const inputValue = + unprocessedValue !== '' + ? parseInt( unprocessedValue, 10 ) + : undefined; + + if ( isNaN( inputValue ) && inputValue !== undefined ) { + setTemporaryInput( unprocessedValue ); + return; + } + setTemporaryInput( null ); + onChange( inputValue ); + }; + + const handleOnBlur = () => { + if ( temporaryInput !== null ) { + setTemporaryInput( null ); + } + }; + + const inputValue = temporaryInput !== null ? temporaryInput : value; + const min = isPx ? COVER_MIN_HEIGHT : 0; + return ( - <BaseControl label={ __( 'Minimum height in pixels' ) } id={ inputId }> - <input - type="number" + <BaseControl label={ __( 'Minimum height of cover' ) } id={ inputId }> + <UnitControl id={ inputId } - onChange={ ( event ) => { - const unprocessedValue = event.target.value; - const inputValue = - unprocessedValue !== '' - ? parseInt( event.target.value, 10 ) - : undefined; - if ( - ( isNaN( inputValue ) || - inputValue < COVER_MIN_HEIGHT ) && - inputValue !== undefined - ) { - setTemporaryInput( event.target.value ); - return; - } - setTemporaryInput( null ); - onChange( inputValue ); - } } - onBlur={ () => { - if ( temporaryInput !== null ) { - setTemporaryInput( null ); - } - } } - value={ temporaryInput !== null ? temporaryInput : value } - min={ COVER_MIN_HEIGHT } + min={ min } + onBlur={ handleOnBlur } + onChange={ handleOnChange } + onUnitChange={ onUnitChange } step="1" + style={ { maxWidth: 80 } } + unit={ unit } + units={ CSS_UNITS } + value={ inputValue } /> </BaseControl> ); -} ); +} const RESIZABLE_BOX_ENABLE_OPTION = { top: false, @@ -227,6 +239,7 @@ function CoverEdit( { focalPoint, hasParallax, minHeight, + minHeightUnit, url, } = attributes; const { @@ -252,15 +265,18 @@ function CoverEdit( { ); const [ temporaryMinHeight, setTemporaryMinHeight ] = useState( null ); - const { removeAllNotices, createErrorNotice } = noticeOperations; + const minHeightWithUnit = minHeightUnit + ? `${ minHeight }${ minHeightUnit }` + : minHeight; + const style = { ...( backgroundType === IMAGE_BACKGROUND_TYPE ? backgroundImageStyles( url ) : {} ), backgroundColor: overlayColor.color, - minHeight: temporaryMinHeight || minHeight, + minHeight: temporaryMinHeight || minHeightWithUnit || undefined, }; if ( gradientValue && ! url ) { @@ -339,9 +355,15 @@ function CoverEdit( { <PanelBody title={ __( 'Dimensions' ) }> <CoverHeightInput value={ temporaryMinHeight || minHeight } + unit={ minHeightUnit } onChange={ ( newMinHeight ) => setAttributes( { minHeight: newMinHeight } ) } + onUnitChange={ ( nextUnit ) => { + setAttributes( { + minHeightUnit: nextUnit, + } ); + } } /> </PanelBody> <PanelColorGradientSettings @@ -436,7 +458,10 @@ function CoverEdit( { 'is-selected': isSelected, } ) } - onResizeStart={ () => toggleSelection( false ) } + onResizeStart={ () => { + setAttributes( { minHeightUnit: 'px' } ); + toggleSelection( false ); + } } onResize={ setTemporaryMinHeight } onResizeStop={ ( newMinHeight ) => { toggleSelection( true ); diff --git a/packages/block-library/src/cover/edit.native.js b/packages/block-library/src/cover/edit.native.js index b3487dce2702c3..9efe434fe5fd47 100644 --- a/packages/block-library/src/cover/edit.native.js +++ b/packages/block-library/src/cover/edit.native.js @@ -2,11 +2,16 @@ * External dependencies */ import { View, TouchableWithoutFeedback } from 'react-native'; -import { default as Video } from 'react-native-video'; +import Video from 'react-native-video'; /** * WordPress dependencies */ +import { + requestImageFailedRetryDialog, + requestImageUploadCancelDialog, + mediaUploadSync, +} from '@wordpress/react-native-bridge'; import { __ } from '@wordpress/i18n'; import { Icon, @@ -25,13 +30,15 @@ import { MEDIA_TYPE_VIDEO, MediaPlaceholder, MediaUpload, + MediaUploadProgress, withColors, __experimentalUseGradient, } from '@wordpress/block-editor'; import { compose, withPreferredColorScheme } from '@wordpress/compose'; import { withSelect } from '@wordpress/data'; -import { useEffect } from '@wordpress/element'; +import { useEffect, useState } from '@wordpress/element'; import { cover as icon, replace } from '@wordpress/icons'; +import { getProtocol } from '@wordpress/url'; /** * Internal dependencies @@ -63,19 +70,27 @@ const COVER_DEFAULT_HEIGHT = 300; const Cover = ( { attributes, getStylesFromColorScheme, - hasChildren, isParentSelected, onFocus, overlayColor, setAttributes, } ) => { - const { backgroundType, dimRatio, focalPoint, minHeight, url } = attributes; + const { + backgroundType, + dimRatio, + focalPoint, + minHeight, + url, + id, + style, + } = attributes; const CONTAINER_HEIGHT = minHeight || COVER_DEFAULT_HEIGHT; const { gradientValue } = __experimentalUseGradient(); const hasBackground = !! ( url || + ( style && style.color && style.color.background ) || attributes.overlayColor || overlayColor.color || gradientValue @@ -93,7 +108,22 @@ const Cover = ( { } }, [ setAttributes ] ); + // sync with local media store + useEffect( mediaUploadSync, [] ); + + // initialize uploading flag to false, awaiting sync + const [ isUploadInProgress, setIsUploadInProgress ] = useState( false ); + + // initialize upload failure flag to true if url is local + const [ didUploadFail, setDidUploadFail ] = useState( + id && getProtocol( url ) === 'file:' + ); + + // don't show failure if upload is in progress + const shouldShowFailure = didUploadFail && ! isUploadInProgress; + const onSelectMedia = ( media ) => { + setDidUploadFail( false ); const onSelect = attributesFromMedia( setAttributes ); // Remove gradient attribute setAttributes( { gradient: undefined, customGradient: undefined } ); @@ -110,22 +140,40 @@ const Cover = ( { setAttributes( { dimRatio: value } ); }; + const onMediaPressed = () => { + if ( isUploadInProgress ) { + requestImageUploadCancelDialog( id ); + } else if ( shouldShowFailure ) { + requestImageFailedRetryDialog( id ); + } + }; + + const [ isVideoLoading, setIsVideoLoading ] = useState( true ); + + const onVideoLoadStart = () => { + setIsVideoLoading( true ); + }; + + const onVideoLoad = () => { + setIsVideoLoading( false ); + }; + + const backgroundColor = getStylesFromColorScheme( + styles.backgroundSolid, + styles.backgroundSolidDark + ); + const overlayStyles = [ styles.overlay, - { + url && { opacity: dimRatio / 100 }, + ! gradientValue && { backgroundColor: - overlayColor && overlayColor.color - ? overlayColor.color - : styles.overlay.color, - opacity: dimRatio / 100, + overlayColor?.color || + style?.color?.background || + styles.overlay.color, }, // While we don't support theme colors we add a default bg color - ! overlayColor.color && ! url - ? getStylesFromColorScheme( - styles.backgroundSolid, - styles.backgroundSolidDark - ) - : {}, + ! overlayColor.color && ! url ? backgroundColor : {}, ]; const placeholderIconStyle = getStylesFromColorScheme( @@ -176,34 +224,52 @@ const Cover = ( { </InspectorControls> ); - const containerStyles = [ - hasChildren && ! isParentSelected && styles.regularMediaPadding, - hasChildren && isParentSelected && styles.innerPadding, - ]; - - const background = ( openMediaOptions, getMediaOptions ) => ( + const renderBackground = ( { + open: openMediaOptions, + getMediaOptions, + } ) => ( <TouchableWithoutFeedback accessible={ ! isParentSelected } + onPress={ onMediaPressed } onLongPress={ openMediaOptions } disabled={ ! isParentSelected } > - <View style={ styles.background }> + <View style={ [ styles.background, backgroundColor ] }> { getMediaOptions() } { isParentSelected && toolbarControls( openMediaOptions ) } - - { /* When the gradient is set as a background the backgroundType is equal to IMAGE_BACKGROUND_TYPE */ } - { IMAGE_BACKGROUND_TYPE === backgroundType && - ( gradientValue ? ( - <LinearGradient - gradientValue={ gradientValue } - style={ styles.background } - /> - ) : ( - <ImageWithFocalPoint - focalPoint={ focalPoint } - url={ url } - /> - ) ) } + <MediaUploadProgress + mediaId={ id } + onUpdateMediaProgress={ () => { + setIsUploadInProgress( true ); + } } + onFinishMediaUploadWithSuccess={ ( { + mediaServerId, + mediaUrl, + } ) => { + setIsUploadInProgress( false ); + setDidUploadFail( false ); + setAttributes( { + id: mediaServerId, + url: mediaUrl, + backgroundType, + } ); + } } + onFinishMediaUploadWithFailure={ () => { + setIsUploadInProgress( false ); + setDidUploadFail( true ); + } } + onMediaUploadStateReset={ () => { + setIsUploadInProgress( false ); + setDidUploadFail( false ); + setAttributes( { id: undefined, url: undefined } ); + } } + /> + { IMAGE_BACKGROUND_TYPE === backgroundType && ( + <ImageWithFocalPoint + focalPoint={ focalPoint } + url={ url } + /> + ) } { VIDEO_BACKGROUND_TYPE === backgroundType && ( <Video muted @@ -211,7 +277,13 @@ const Cover = ( { repeat resizeMode={ 'cover' } source={ { uri: url } } - style={ styles.background } + onLoad={ onVideoLoad } + onLoadStart={ onVideoLoadStart } + style={ [ + styles.background, + // Hide Video component since it has black background while loading the source + { opacity: isVideoLoading ? 0 : 1 }, + ] } /> ) } </View> @@ -220,9 +292,10 @@ const Cover = ( { if ( ! hasBackground ) { return ( - <View style={ containerStyles }> + <View> <MediaPlaceholder - __experimentalOnlyMediaLibrary + // eslint-disable-next-line no-undef + __experimentalOnlyMediaLibrary={ ! __DEV__ } icon={ placeholderIcon } labels={ { title: __( 'Cover' ), @@ -236,33 +309,46 @@ const Cover = ( { } return ( - <View style={ containerStyles }> + <View style={ styles.backgroundContainer }> { controls } - <View style={ styles.backgroundContainer }> - <View - pointerEvents="box-none" - style={ [ - styles.content, - { minHeight: CONTAINER_HEIGHT }, - ] } - > - <InnerBlocks template={ INNER_BLOCKS_TEMPLATE } /> - </View> - { /* We don't render overlay on top of gradient */ } - { ! gradientValue && ( - <View pointerEvents="none" style={ overlayStyles } /> - ) } + <View + pointerEvents="box-none" + style={ [ styles.content, { minHeight: CONTAINER_HEIGHT } ] } + > + <InnerBlocks template={ INNER_BLOCKS_TEMPLATE } /> + </View> - <MediaUpload - __experimentalOnlyMediaLibrary - allowedTypes={ ALLOWED_MEDIA_TYPES } - onSelect={ onSelectMedia } - render={ ( { open, getMediaOptions } ) => { - return background( open, getMediaOptions ); - } } - /> + <View pointerEvents="none" style={ overlayStyles }> + { gradientValue && ( + <LinearGradient + gradientValue={ gradientValue } + style={ styles.background } + /> + ) } </View> + + <MediaUpload + // eslint-disable-next-line no-undef + __experimentalOnlyMediaLibrary={ ! __DEV__ } + allowedTypes={ ALLOWED_MEDIA_TYPES } + onSelect={ onSelectMedia } + render={ renderBackground } + /> + + { shouldShowFailure && ( + <View + pointerEvents="none" + style={ styles.uploadFailedContainer } + > + <View style={ styles.uploadFailed }> + <Icon + icon={ 'warning' } + { ...styles.uploadFailedIcon } + /> + </View> + </View> + ) } </View> ); }; @@ -270,15 +356,11 @@ const Cover = ( { export default compose( [ withColors( { overlayColor: 'background-color' } ), withSelect( ( select, { clientId } ) => { - const { getSelectedBlockClientId, getBlockCount } = select( - 'core/block-editor' - ); + const { getSelectedBlockClientId } = select( 'core/block-editor' ); const selectedBlockClientId = getSelectedBlockClientId(); - const hasChildren = getBlockCount( clientId ); return { - hasChildren, isParentSelected: selectedBlockClientId === clientId, }; } ), diff --git a/packages/block-library/src/cover/editor.scss b/packages/block-library/src/cover/editor.scss index cca0e8a751e099..31faa3872936d0 100644 --- a/packages/block-library/src/cover/editor.scss +++ b/packages/block-library/src/cover/editor.scss @@ -9,10 +9,6 @@ width: 100%; } - .block-editor-block-list__block { - color: $light-gray-100; - } - // The .wp-block-cover class is used just to increase selector specificity. .wp-block-cover__inner-container { // Avoid text align inherit from cover image align. diff --git a/packages/block-library/src/cover/save.js b/packages/block-library/src/cover/save.js index 8cb56dbe4752d5..4e45fa41347b58 100644 --- a/packages/block-library/src/cover/save.js +++ b/packages/block-library/src/cover/save.js @@ -33,13 +33,17 @@ export default function save( { attributes } ) { hasParallax, overlayColor, url, - minHeight, + minHeight: minHeightProp, + minHeightUnit, } = attributes; const overlayColorClass = getColorClassName( 'background-color', overlayColor ); const gradientClass = __experimentalGetGradientClass( gradient ); + const minHeight = minHeightUnit + ? `${ minHeightProp }${ minHeightUnit }` + : minHeightProp; const style = backgroundType === IMAGE_BACKGROUND_TYPE diff --git a/packages/block-library/src/cover/shared.js b/packages/block-library/src/cover/shared.js index bf1e794606aa3d..1fba24ccd1c68f 100644 --- a/packages/block-library/src/cover/shared.js +++ b/packages/block-library/src/cover/shared.js @@ -5,6 +5,14 @@ export function backgroundImageStyles( url ) { return url ? { backgroundImage: `url(${ url })` } : {}; } +export const CSS_UNITS = [ + { value: 'px', label: 'px', default: 430 }, + { value: 'em', label: 'em', default: 20 }, + { value: 'rem', label: 'rem', default: 20 }, + { value: 'vw', label: 'vw', default: 20 }, + { value: 'vh', label: 'vh', default: 50 }, +]; + export function dimRatioToClass( ratio ) { return ratio === 0 || ratio === 50 || ! ratio ? null diff --git a/packages/block-library/src/cover/style.native.scss b/packages/block-library/src/cover/style.native.scss index 2141f715a2b7e5..59d23d8999b31d 100644 --- a/packages/block-library/src/cover/style.native.scss +++ b/packages/block-library/src/cover/style.native.scss @@ -8,18 +8,6 @@ fill: $white; } -.innerPadding { - padding: $block-selected-to-content; -} - -.regularMediaPadding { - padding: $block-edge-to-content; -} - -.denseMediaPadding { - padding: $block-media-container-to-content; -} - .backgroundContainer { overflow: hidden; width: 100%; @@ -29,6 +17,7 @@ .content { justify-content: center; width: 100%; + padding: $block-edge-to-content; z-index: 3; } @@ -57,3 +46,28 @@ .backgroundSolidDark { background-color: $background-dark-secondary; } + +.uploadFailedContainer { + position: absolute; + width: 100%; + height: 100%; + padding: 8px; + justify-content: flex-start; + align-items: flex-end; + z-index: 3; +} + +.uploadFailed { + width: 24px; + height: 24px; + border-radius: 12px; + justify-content: center; + align-items: center; + background-color: #fff; +} + +.uploadFailedIcon { + fill: $red-40; + width: 100%; + height: 100%; +} diff --git a/packages/block-library/src/cover/style.scss b/packages/block-library/src/cover/style.scss index 739742d1e62270..1742bf45f9de5a 100644 --- a/packages/block-library/src/cover/style.scss +++ b/packages/block-library/src/cover/style.scss @@ -1,7 +1,6 @@ .wp-block-cover-image, .wp-block-cover { position: relative; - background-color: $black; background-size: cover; background-position: center center; min-height: 430px; @@ -11,7 +10,6 @@ justify-content: center; align-items: center; overflow: hidden; - &.has-parallax { background-attachment: fixed; @@ -28,9 +26,13 @@ } } - &.has-background-dim::before { - content: ""; - background-color: inherit; + &.has-background-dim { + background-color: $black; + + &::before { + content: ""; + background-color: inherit; + } } &.has-background-dim:not(.has-background-gradient)::before, diff --git a/packages/block-library/src/embed/editor.scss b/packages/block-library/src/embed/editor.scss index 342b4fe1b116b2..f84b5b886bd10d 100644 --- a/packages/block-library/src/embed/editor.scss +++ b/packages/block-library/src/embed/editor.scss @@ -7,17 +7,6 @@ // therefore the video doesn't intrinsically clear floats like an image does. clear: both; - // Apply a min-width, or the embed can collapse when floated. - // Instagram widgets have a min-width of 326px, so go a bit beyond that. - @include break-small() { - min-width: 360px; - - // The placeholder should not have this min-width. - &.components-placeholder { - min-width: 0; - } - } - &.is-loading { display: flex; flex-direction: column; diff --git a/packages/block-library/src/embed/embed-preview.js b/packages/block-library/src/embed/embed-preview.js index 419ef17c7bb115..0e70f84729acc6 100644 --- a/packages/block-library/src/embed/embed-preview.js +++ b/packages/block-library/src/embed/embed-preview.js @@ -73,8 +73,8 @@ class EmbedPreview extends Component { .splice( parsedHost.length - 2, parsedHost.length - 1 ) .join( '.' ); const cannotPreview = includes( HOSTS_NO_PREVIEWS, parsedHostBaseUrl ); - // translators: %s: host providing embed content e.g: www.youtube.com const iframeTitle = sprintf( + // translators: %s: host providing embed content e.g: www.youtube.com __( 'Embedded content from %s' ), parsedHostBaseUrl ); @@ -125,8 +125,8 @@ class EmbedPreview extends Component { <a href={ url }>{ url }</a> </p> <p className="components-placeholder__error"> - { /* translators: %s: host providing embed content e.g: www.youtube.com */ - sprintf( + { sprintf( + /* translators: %s: host providing embed content e.g: www.youtube.com */ __( "Embedded content from %s can't be previewed in the editor." ), diff --git a/packages/block-library/src/embed/icons.js b/packages/block-library/src/embed/icons.js index 1ad0c76cf1c634..292a3d336aaaa2 100644 --- a/packages/block-library/src/embed/icons.js +++ b/packages/block-library/src/embed/icons.js @@ -98,7 +98,7 @@ export const embedTumblrIcon = { foreground: '#35465c', src: ( <SVG viewBox="0 0 24 24"> - <Path d="M19 3H5c-1.105 0-2 .895-2 2v14c0 1.105.895 2 2 2h14c1.105 0 2-.895 2-2V5c0-1.105-.895-2-2-2zm-5.57 14.265c-2.445.042-3.37-1.742-3.37-2.998V10.6H8.922V9.15c1.703-.615 2.113-2.15 2.21-3.026.006-.06.053-.084.08-.084h1.645V8.9h2.246v1.7H12.85v3.495c.008.476.182 1.13 1.08 1.107.3-.008.698-.094.907-.194l.54 1.6c-.205.297-1.12.642-1.946.657z" /> + <Path d="M19 3H5a2 2 0 00-2 2v14c0 1.1.9 2 2 2h14a2 2 0 002-2V5a2 2 0 00-2-2zm-5.69 14.66c-2.72 0-3.1-1.9-3.1-3.16v-3.56H8.49V8.99c1.7-.62 2.54-1.99 2.64-2.87 0-.06.06-.41.06-.58h1.9v3.1h2.17v2.3h-2.18v3.1c0 .47.13 1.3 1.2 1.26h1.1v2.36c-1.01.02-2.07 0-2.07 0z" /> </SVG> ), }; diff --git a/packages/block-library/src/embed/style.scss b/packages/block-library/src/embed/style.scss index 4abaf5b7778f57..0905f04dd8e4e8 100644 --- a/packages/block-library/src/embed/style.scss +++ b/packages/block-library/src/embed/style.scss @@ -1,6 +1,6 @@ // Apply max-width to floated items that have no intrinsic width -.block-editor-block-list__block[data-type="core/embed"][data-align="left"], -.block-editor-block-list__block[data-type="core/embed"][data-align="right"], +.block-editor-block-list__block[data-type*="core-embed"][data-align="left"] .is-block-content, +.block-editor-block-list__block[data-type*="core-embed"][data-align="right"] .is-block-content, .wp-block-embed.alignleft, .wp-block-embed.alignright { // Instagram widgets have a min-width of 326px, so go a bit beyond that. diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index c3b556b683503d..3f77212f71990a 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -20,11 +20,10 @@ import { import { compose } from '@wordpress/compose'; import { PanelBody, - RangeControl, SelectControl, - StepperControl, ToggleControl, withNotices, + RangeControl, } from '@wordpress/components'; import { MediaPlaceholder, InspectorControls } from '@wordpress/block-editor'; import { Component, Platform } from '@wordpress/element'; @@ -40,7 +39,6 @@ import { sharedIcon } from './shared-icon'; import { defaultColumnsNumber, pickRelevantMediaFiles } from './shared'; import Gallery from './gallery'; -const ColumnsControl = Platform.OS === 'web' ? RangeControl : StepperControl; const MAX_COLUMNS = 8; const linkOptions = [ { value: 'attachment', label: __( 'Attachment Page' ) }, @@ -67,6 +65,11 @@ const MOBILE_CONTROL_PROPS_SEPARATOR_NONE = Platform.select( { native: { separatorType: 'none' }, } ); +const MOBILE_CONTROL_PROPS_RANGE_CONTROL = Platform.select( { + web: {}, + native: { type: 'stepper' }, +} ); + class GalleryEdit extends Component { constructor() { super( ...arguments ); @@ -393,13 +396,14 @@ class GalleryEdit extends Component { <InspectorControls> <PanelBody title={ __( 'Gallery settings' ) }> { images.length > 1 && ( - <ColumnsControl + <RangeControl label={ __( 'Columns' ) } - { ...MOBILE_CONTROL_PROPS } value={ columns } onChange={ this.setColumnsNumber } min={ 1 } max={ Math.min( MAX_COLUMNS, images.length ) } + { ...MOBILE_CONTROL_PROPS } + { ...MOBILE_CONTROL_PROPS_RANGE_CONTROL } required /> ) } diff --git a/packages/block-library/src/gallery/gallery.js b/packages/block-library/src/gallery/gallery.js index d0f0c03d9b3260..53c319d26c0594 100644 --- a/packages/block-library/src/gallery/gallery.js +++ b/packages/block-library/src/gallery/gallery.js @@ -51,8 +51,8 @@ export const Gallery = ( props ) => { > <ul className="blocks-gallery-grid"> { images.map( ( img, index ) => { - /* translators: %1$d is the order number of the image, %2$d is the total number of images. */ const ariaLabel = sprintf( + /* translators: 1: the order number of the image. 2: the total number of images. */ __( 'image %1$d of %2$d in gallery' ), index + 1, images.length diff --git a/packages/block-library/src/gallery/gallery.native.js b/packages/block-library/src/gallery/gallery.native.js index 2bdb436ba30863..6f6d53c5425ace 100644 --- a/packages/block-library/src/gallery/gallery.native.js +++ b/packages/block-library/src/gallery/gallery.native.js @@ -88,8 +88,8 @@ export const Gallery = ( props ) => { } > { images.map( ( img, index ) => { - /* translators: %1$d is the order number of the image, %2$d is the total number of images. */ const ariaLabel = sprintf( + /* translators: 1: the order number of the image. 2: the total number of images. */ __( 'image %1$d of %2$d in gallery' ), index + 1, images.length diff --git a/packages/block-library/src/group/block.json b/packages/block-library/src/group/block.json index 8883720bbc2aab..9359f8101603ba 100644 --- a/packages/block-library/src/group/block.json +++ b/packages/block-library/src/group/block.json @@ -2,17 +2,9 @@ "name": "core/group", "category": "layout", "attributes": { - "backgroundColor": { - "type": "string" - }, - "customBackgroundColor": { - "type": "string" - }, - "textColor": { - "type": "string" - }, - "customTextColor": { - "type": "string" + "tagName": { + "type": "string", + "default": "div" } } } diff --git a/packages/block-library/src/group/deprecated.js b/packages/block-library/src/group/deprecated.js index 31440c003f8669..3e6d394197ffd6 100644 --- a/packages/block-library/src/group/deprecated.js +++ b/packages/block-library/src/group/deprecated.js @@ -2,13 +2,94 @@ * External dependencies */ import classnames from 'classnames'; +import { omit } from 'lodash'; /** * WordPress dependencies */ import { InnerBlocks, getColorClassName } from '@wordpress/block-editor'; +const migrateAttributes = ( attributes ) => { + if ( ! attributes.tagName ) { + attributes = { + ...attributes, + tagName: 'div', + }; + } + + if ( ! attributes.customTextColor && ! attributes.customBackgroundColor ) { + return attributes; + } + const style = { color: {} }; + if ( attributes.customTextColor ) { + style.color.text = attributes.customTextColor; + } + if ( attributes.customBackgroundColor ) { + style.color.background = attributes.customBackgroundColor; + } + return { + ...omit( attributes, [ 'customTextColor', 'customBackgroundColor' ] ), + style, + }; +}; + const deprecated = [ + // Version of the block without global styles support + { + attributes: { + backgroundColor: { + type: 'string', + }, + customBackgroundColor: { + type: 'string', + }, + textColor: { + type: 'string', + }, + customTextColor: { + type: 'string', + }, + }, + supports: { + align: [ 'wide', 'full' ], + anchor: true, + html: false, + }, + migrate: migrateAttributes, + save( { attributes } ) { + const { + backgroundColor, + customBackgroundColor, + textColor, + customTextColor, + } = attributes; + + const backgroundClass = getColorClassName( + 'background-color', + backgroundColor + ); + const textClass = getColorClassName( 'color', textColor ); + const className = classnames( backgroundClass, textClass, { + 'has-text-color': textColor || customTextColor, + 'has-background': backgroundColor || customBackgroundColor, + } ); + + const styles = { + backgroundColor: backgroundClass + ? undefined + : customBackgroundColor, + color: textClass ? undefined : customTextColor, + }; + + return ( + <div className={ className } style={ styles }> + <div className="wp-block-group__inner-container"> + <InnerBlocks.Content /> + </div> + </div> + ); + }, + }, // Version of the group block with a bug that made text color class not applied. { attributes: { @@ -25,6 +106,7 @@ const deprecated = [ type: 'string', }, }, + migrate: migrateAttributes, supports: { align: [ 'wide', 'full' ], anchor: true, @@ -79,6 +161,7 @@ const deprecated = [ anchor: true, html: false, }, + migrate: migrateAttributes, save( { attributes } ) { const { backgroundColor, customBackgroundColor } = attributes; diff --git a/packages/block-library/src/group/edit.js b/packages/block-library/src/group/edit.js index c0d195c997f017..6a7989f8a8df96 100644 --- a/packages/block-library/src/group/edit.js +++ b/packages/block-library/src/group/edit.js @@ -1,61 +1,36 @@ /** * WordPress dependencies */ -import { withSelect } from '@wordpress/data'; -import { compose } from '@wordpress/compose'; +import { useSelect } from '@wordpress/data'; import { InnerBlocks, - __experimentalUseColors, __experimentalBlock as Block, } from '@wordpress/block-editor'; -import { useRef } from '@wordpress/element'; -function GroupEdit( { hasInnerBlocks, className } ) { - const ref = useRef(); - const { - TextColor, - BackgroundColor, - InspectorControlsColorPanel, - } = __experimentalUseColors( - [ - { name: 'textColor', property: 'color' }, - { name: 'backgroundColor', className: 'has-background' }, - ], - { - contrastCheckers: [ { backgroundColor: true, textColor: true } ], - colorDetector: { targetRef: ref }, - } +function GroupEdit( { attributes, className, clientId } ) { + const hasInnerBlocks = useSelect( + ( select ) => { + const { getBlock } = select( 'core/block-editor' ); + const block = getBlock( clientId ); + return !! ( block && block.innerBlocks.length ); + }, + [ clientId ] ); + const BlockWrapper = Block[ attributes.tagName ]; return ( - <> - { InspectorControlsColorPanel } - <BackgroundColor> - <TextColor> - <Block.div className={ className } ref={ ref }> - <div className="wp-block-group__inner-container"> - <InnerBlocks - renderAppender={ - ! hasInnerBlocks && - InnerBlocks.ButtonBlockAppender - } - /> - </div> - </Block.div> - </TextColor> - </BackgroundColor> - </> + <BlockWrapper className={ className }> + <div className="wp-block-group__inner-container"> + <InnerBlocks + renderAppender={ + hasInnerBlocks + ? undefined + : () => <InnerBlocks.ButtonBlockAppender /> + } + /> + </div> + </BlockWrapper> ); } -export default compose( [ - withSelect( ( select, { clientId } ) => { - const { getBlock } = select( 'core/block-editor' ); - - const block = getBlock( clientId ); - - return { - hasInnerBlocks: !! ( block && block.innerBlocks.length ), - }; - } ), -] )( GroupEdit ); +export default GroupEdit; diff --git a/packages/block-library/src/group/edit.native.js b/packages/block-library/src/group/edit.native.js index a1b261f3340c6c..257ba8b4e628c7 100644 --- a/packages/block-library/src/group/edit.native.js +++ b/packages/block-library/src/group/edit.native.js @@ -33,9 +33,11 @@ function GroupEdit( { hasInnerBlocks, isSelected, getStylesFromColorScheme } ) { } return ( - <InnerBlocks - renderAppender={ isSelected && InnerBlocks.ButtonBlockAppender } - /> + <View style={ isSelected && hasInnerBlocks && styles.innerBlocks }> + <InnerBlocks + renderAppender={ isSelected && InnerBlocks.ButtonBlockAppender } + /> + </View> ); } diff --git a/packages/block-library/src/group/editor.native.scss b/packages/block-library/src/group/editor.native.scss index 2f426176fe22a2..7f8a9ce1322462 100644 --- a/packages/block-library/src/group/editor.native.scss +++ b/packages/block-library/src/group/editor.native.scss @@ -22,3 +22,7 @@ margin-left: 0; margin-right: 0; } + +.innerBlocks { + margin-bottom: $block-edge-to-content; +} diff --git a/packages/block-library/src/group/index.js b/packages/block-library/src/group/index.js index c977195156b73d..d07cf54f7256d8 100644 --- a/packages/block-library/src/group/index.js +++ b/packages/block-library/src/group/index.js @@ -29,8 +29,12 @@ export const settings = { ], example: { attributes: { - customBackgroundColor: '#ffffff', - customTextColor: '#000000', + style: { + color: { + text: '#000000', + background: '#ffffff', + }, + }, }, innerBlocks: [ { @@ -88,6 +92,7 @@ export const settings = { anchor: true, html: false, lightBlockWrapper: true, + __experimentalColor: { gradients: true }, }, transforms: { from: [ diff --git a/packages/block-library/src/group/save.js b/packages/block-library/src/group/save.js index 6d248efbfc2579..f24c9f37cdf409 100644 --- a/packages/block-library/src/group/save.js +++ b/packages/block-library/src/group/save.js @@ -1,41 +1,16 @@ -/** - * External dependencies - */ -import classnames from 'classnames'; - /** * WordPress dependencies */ -import { InnerBlocks, getColorClassName } from '@wordpress/block-editor'; +import { InnerBlocks } from '@wordpress/block-editor'; export default function save( { attributes } ) { - const { - backgroundColor, - customBackgroundColor, - textColor, - customTextColor, - } = attributes; - - const backgroundClass = getColorClassName( - 'background-color', - backgroundColor - ); - const textClass = getColorClassName( 'color', textColor ); - const className = classnames( backgroundClass, textClass, { - 'has-text-color': textColor || customTextColor, - 'has-background': backgroundColor || customBackgroundColor, - } ); - - const styles = { - backgroundColor: backgroundClass ? undefined : customBackgroundColor, - color: textClass ? undefined : customTextColor, - }; + const { tagName: Tag } = attributes; return ( - <div className={ className } style={ styles }> + <Tag> <div className="wp-block-group__inner-container"> <InnerBlocks.Content /> </div> - </div> + </Tag> ); } diff --git a/packages/block-library/src/heading/block.json b/packages/block-library/src/heading/block.json index 2c47b2c7096521..120bece3d39ae3 100644 --- a/packages/block-library/src/heading/block.json +++ b/packages/block-library/src/heading/block.json @@ -17,12 +17,6 @@ }, "placeholder": { "type": "string" - }, - "textColor": { - "type": "string" - }, - "customTextColor": { - "type": "string" } } } diff --git a/packages/block-library/src/heading/deprecated.js b/packages/block-library/src/heading/deprecated.js index fffa0f9b4e7976..7a43fc9d5b8689 100644 --- a/packages/block-library/src/heading/deprecated.js +++ b/packages/block-library/src/heading/deprecated.js @@ -2,6 +2,7 @@ * External dependencies */ import classnames from 'classnames'; +import { omit } from 'lodash'; /** * WordPress dependencies @@ -30,17 +31,77 @@ const blockAttributes = { placeholder: { type: 'string', }, - textColor: { - type: 'string', - }, - customTextColor: { - type: 'string', - }, +}; + +const migrateCustomColors = ( attributes ) => { + if ( ! attributes.customTextColor ) { + return attributes; + } + const style = { + color: { + text: attributes.customTextColor, + }, + }; + return { + ...omit( attributes, [ 'customTextColor' ] ), + style, + }; }; const deprecated = [ { - attributes: blockAttributes, + supports: blockSupports, + attributes: { + ...blockAttributes, + customTextColor: { + type: 'string', + }, + textColor: { + type: 'string', + }, + }, + migrate: migrateCustomColors, + save( { attributes } ) { + const { + align, + content, + customTextColor, + level, + textColor, + } = attributes; + const tagName = 'h' + level; + + const textClass = getColorClassName( 'color', textColor ); + + const className = classnames( { + [ textClass ]: textClass, + 'has-text-color': textColor || customTextColor, + [ `has-text-align-${ align }` ]: align, + } ); + + return ( + <RichText.Content + className={ className ? className : undefined } + tagName={ tagName } + style={ { + color: textClass ? undefined : customTextColor, + } } + value={ content } + /> + ); + }, + }, + { + attributes: { + ...blockAttributes, + customTextColor: { + type: 'string', + }, + textColor: { + type: 'string', + }, + }, + migrate: migrateCustomColors, save( { attributes } ) { const { align, @@ -73,7 +134,16 @@ const deprecated = [ }, { supports: blockSupports, - attributes: blockAttributes, + attributes: { + ...blockAttributes, + customTextColor: { + type: 'string', + }, + textColor: { + type: 'string', + }, + }, + migrate: migrateCustomColors, save( { attributes } ) { const { align, diff --git a/packages/block-library/src/heading/edit.js b/packages/block-library/src/heading/edit.js index 3e43660a300efe..28f9a6da5be576 100644 --- a/packages/block-library/src/heading/edit.js +++ b/packages/block-library/src/heading/edit.js @@ -12,93 +12,91 @@ import HeadingToolbar from './heading-toolbar'; * WordPress dependencies */ import { __ } from '@wordpress/i18n'; -import { PanelBody } from '@wordpress/components'; +import { PanelBody, __experimentalText as Text } from '@wordpress/components'; import { createBlock } from '@wordpress/blocks'; import { AlignmentToolbar, BlockControls, InspectorControls, RichText, - __experimentalUseColors, __experimentalBlock as Block, } from '@wordpress/block-editor'; -import { useRef } from '@wordpress/element'; +import { Platform } from '@wordpress/element'; function HeadingEdit( { attributes, setAttributes, mergeBlocks, onReplace } ) { - const ref = useRef(); - const { TextColor, InspectorControlsColorPanel } = __experimentalUseColors( - [ { name: 'textColor', property: 'color' } ], - { - contrastCheckers: { backgroundColor: true, textColor: true }, - colorDetector: { targetRef: ref }, - }, - [] - ); - - const { align, content, level, placeholder } = attributes; + const { align, content, level, placeholder, style } = attributes; const tagName = 'h' + level; + const isAndroid = Platform.select( { + android: true, + native: false, + web: false, + } ); + + const styles = { + color: style && style.color && style.color.text, + }; return ( <> <BlockControls> <HeadingToolbar - minLevel={ 2 } - maxLevel={ 5 } + minLevel={ Platform.OS === 'web' ? 2 : 1 } + maxLevel={ Platform.OS === 'web' ? 5 : 7 } selectedLevel={ level } onChange={ ( newLevel ) => setAttributes( { level: newLevel } ) } /> - <AlignmentToolbar - value={ align } - onChange={ ( nextAlign ) => { - setAttributes( { align: nextAlign } ); - } } - /> - </BlockControls> - <InspectorControls> - <PanelBody title={ __( 'Heading settings' ) }> - <p>{ __( 'Level' ) }</p> - <HeadingToolbar - isCollapsed={ false } - minLevel={ 1 } - maxLevel={ 7 } - selectedLevel={ level } - onChange={ ( newLevel ) => - setAttributes( { level: newLevel } ) - } + { ! isAndroid && ( + <AlignmentToolbar + value={ align } + onChange={ ( nextAlign ) => { + setAttributes( { align: nextAlign } ); + } } /> - </PanelBody> - </InspectorControls> - { InspectorControlsColorPanel } - <TextColor> - <RichText - ref={ ref } - identifier="content" - tagName={ Block[ tagName ] } - value={ content } - onChange={ ( value ) => - setAttributes( { content: value } ) + ) } + </BlockControls> + { Platform.OS === 'web' && ( + <InspectorControls> + <PanelBody title={ __( 'Heading settings' ) }> + <Text variant="label">{ __( 'Level' ) }</Text> + <HeadingToolbar + isCollapsed={ false } + minLevel={ 1 } + maxLevel={ 7 } + selectedLevel={ level } + onChange={ ( newLevel ) => + setAttributes( { level: newLevel } ) + } + /> + </PanelBody> + </InspectorControls> + ) } + <RichText + identifier="content" + tagName={ Block[ tagName ] } + value={ content } + onChange={ ( value ) => setAttributes( { content: value } ) } + onMerge={ mergeBlocks } + onSplit={ ( value ) => { + if ( ! value ) { + return createBlock( 'core/paragraph' ); } - onMerge={ mergeBlocks } - onSplit={ ( value ) => { - if ( ! value ) { - return createBlock( 'core/paragraph' ); - } - return createBlock( 'core/heading', { - ...attributes, - content: value, - } ); - } } - onReplace={ onReplace } - onRemove={ () => onReplace( [] ) } - className={ classnames( { - [ `has-text-align-${ align }` ]: align, - } ) } - placeholder={ placeholder || __( 'Write heading…' ) } - /> - </TextColor> + return createBlock( 'core/heading', { + ...attributes, + content: value, + } ); + } } + onReplace={ onReplace } + onRemove={ () => onReplace( [] ) } + className={ classnames( { + [ `has-text-align-${ align }` ]: align, + } ) } + placeholder={ placeholder || __( 'Write heading…' ) } + textAlign={ align } + style={ styles } + /> </> ); } diff --git a/packages/block-library/src/heading/edit.native.js b/packages/block-library/src/heading/edit.native.js deleted file mode 100644 index 8d8d8b49aef99a..00000000000000 --- a/packages/block-library/src/heading/edit.native.js +++ /dev/null @@ -1,81 +0,0 @@ -/** - * Internal dependencies - */ -import HeadingToolbar from './heading-toolbar'; - -/** - * External dependencies - */ -import { View } from 'react-native'; - -/** - * WordPress dependencies - */ -import { __ } from '@wordpress/i18n'; -import { - RichText, - BlockControls, - __experimentalUseColors, -} from '@wordpress/block-editor'; -import { createBlock } from '@wordpress/blocks'; - -const HeadingEdit = ( { - attributes, - mergeBlocks, - onFocus, - onReplace, - setAttributes, - style, -} ) => { - const { align, content, level, placeholder } = attributes; - - /* eslint-disable @wordpress/no-unused-vars-before-return */ - const { TextColor } = __experimentalUseColors( [ - { name: 'textColor', property: 'color' }, - ] ); - /* eslint-enable @wordpress/no-unused-vars-before-return */ - - return ( - <View onAccessibilityTap={ onFocus }> - <BlockControls> - <HeadingToolbar - minLevel={ 2 } - maxLevel={ 7 } - selectedLevel={ level } - onChange={ ( newLevel ) => - setAttributes( { level: newLevel } ) - } - isCollapsed={ false } - /> - </BlockControls> - <TextColor> - <RichText - identifier="content" - tagName={ 'h' + level } - value={ content } - style={ style } - onChange={ ( value ) => - setAttributes( { content: value } ) - } - onMerge={ mergeBlocks } - onSplit={ ( value ) => { - if ( ! value ) { - return createBlock( 'core/paragraph' ); - } - - return createBlock( 'core/heading', { - ...attributes, - content: value, - } ); - } } - onReplace={ onReplace } - onRemove={ () => onReplace( [] ) } - placeholder={ placeholder || __( 'Write heading…' ) } - textAlign={ align } - /> - </TextColor> - </View> - ); -}; - -export default HeadingEdit; diff --git a/packages/block-library/src/heading/heading-level-icon.js b/packages/block-library/src/heading/heading-level-icon.js index 29a60cd93d7217..eef2b3af3b5e7e 100644 --- a/packages/block-library/src/heading/heading-level-icon.js +++ b/packages/block-library/src/heading/heading-level-icon.js @@ -18,8 +18,8 @@ export default function HeadingLevelIcon( { level, isPressed = false } ) { return ( <SVG - width="20" - height="20" + width="24" + height="24" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" isPressed={ isPressed } diff --git a/packages/block-library/src/heading/index.js b/packages/block-library/src/heading/index.js index de82e618486222..2b9eac45e956d7 100644 --- a/packages/block-library/src/heading/index.js +++ b/packages/block-library/src/heading/index.js @@ -34,6 +34,9 @@ export const settings = { anchor: true, __unstablePasteTextInline: true, lightBlockWrapper: true, + __experimentalColor: true, + __experimentalLineHeight: true, + __experimentalFontSize: true, }, example: { attributes: { diff --git a/packages/block-library/src/heading/save.js b/packages/block-library/src/heading/save.js index 5b2adacec2a633..00ecf40e1c27ce 100644 --- a/packages/block-library/src/heading/save.js +++ b/packages/block-library/src/heading/save.js @@ -6,17 +6,13 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import { getColorClassName, RichText } from '@wordpress/block-editor'; +import { RichText } from '@wordpress/block-editor'; export default function save( { attributes } ) { - const { align, content, customTextColor, level, textColor } = attributes; + const { align, content, level } = attributes; const tagName = 'h' + level; - const textClass = getColorClassName( 'color', textColor ); - const className = classnames( { - [ textClass ]: textClass, - 'has-text-color': textColor || customTextColor, [ `has-text-align-${ align }` ]: align, } ); @@ -24,9 +20,6 @@ export default function save( { attributes } ) { <RichText.Content className={ className ? className : undefined } tagName={ tagName } - style={ { - color: textClass ? undefined : customTextColor, - } } value={ content } /> ); diff --git a/packages/block-library/src/heading/style.scss b/packages/block-library/src/heading/style.scss new file mode 100644 index 00000000000000..31a6989c39c817 --- /dev/null +++ b/packages/block-library/src/heading/style.scss @@ -0,0 +1,10 @@ +h1, +h2, +h3, +h4, +h5, +h6 { + &.has-background { + padding: $block-bg-padding--v $block-bg-padding--h; + } +} diff --git a/packages/block-library/src/image/edit.js b/packages/block-library/src/image/edit.js index a5b9893aa57ca2..30ddaefd89602e 100644 --- a/packages/block-library/src/image/edit.js +++ b/packages/block-library/src/image/edit.js @@ -33,7 +33,7 @@ import { __experimentalImageSizeControl as ImageSizeControl, __experimentalImageURLInputUI as ImageURLInputUI, } from '@wordpress/block-editor'; -import { Component, Fragment } from '@wordpress/element'; +import { Component } from '@wordpress/element'; import { __, sprintf } from '@wordpress/i18n'; import { getPath } from '@wordpress/url'; import { withViewportMatch } from '@wordpress/viewport'; @@ -509,17 +509,23 @@ export class ImageEdit extends Component { </> ); - const AlignmentWrapper = needsAlignmentWrapper ? Block.div : Fragment; - const BlockContentWrapper = needsAlignmentWrapper - ? 'figure' - : Block.figure; // Disable reason: Each block can be selected by clicking on it /* eslint-disable jsx-a11y/click-events-have-key-events */ return ( <> { controls } - <AlignmentWrapper> - <BlockContentWrapper className={ classes }> + <div + className={ + // Ideally these classes are not needed, and ideally, we + // provide an alignment wrapper component that the block + // can wrap around the block or we build it into + // Block.*. + needsAlignmentWrapper + ? 'wp-block block-editor-block-list__block' + : undefined + } + > + <Block.figure className={ classes }> <ImageSize src={ url } dirtynessTrigger={ align }> { ( sizes ) => { const { @@ -535,6 +541,7 @@ export class ImageEdit extends Component { defaultedAlt = alt; } else if ( filename ) { defaultedAlt = sprintf( + /* translators: %s: file name */ __( 'This image has an empty alt attribute; its file name is %s' ), @@ -697,8 +704,8 @@ export class ImageEdit extends Component { ) } { mediaPlaceholder } - </BlockContentWrapper> - </AlignmentWrapper> + </Block.figure> + </div> </> ); /* eslint-enable jsx-a11y/click-events-have-key-events */ diff --git a/packages/block-library/src/image/edit.native.js b/packages/block-library/src/image/edit.native.js index dcaca86962b2cb..b12126e57a8253 100644 --- a/packages/block-library/src/image/edit.native.js +++ b/packages/block-library/src/image/edit.native.js @@ -9,8 +9,6 @@ import { TouchableWithoutFeedback, Dimensions, } from 'react-native'; -import { isEmpty, get, find, map } from 'lodash'; - /** * WordPress dependencies */ @@ -20,8 +18,12 @@ import { requestImageFailedRetryDialog, requestImageUploadCancelDialog, requestImageFullscreenPreview, - showMediaEditorButton, } from '@wordpress/react-native-bridge'; +import { isEmpty, get, find, map } from 'lodash'; + +/** + * WordPress dependencies + */ import { CycleSelectControl, Icon, @@ -295,6 +297,7 @@ export class ImageEdit extends React.Component { const mediaAttributes = { id: media.id, url: media.url, + caption: media.caption, }; let additionalAttributes; @@ -390,7 +393,6 @@ export class ImageEdit extends React.Component { <BlockAlignmentToolbar value={ align } onChange={ this.updateAlignment } - isCollapsed={ false } /> </BlockControls> ); @@ -607,8 +609,7 @@ export class ImageEdit extends React.Component { ! isUploadInProgress && ! isUploadFailed && finalWidth && - finalHeight && - showMediaEditorButton && ( + finalHeight && ( <MediaEdit allowedTypes={ [ MEDIA_TYPE_IMAGE, diff --git a/packages/block-library/src/image/editor.scss b/packages/block-library/src/image/editor.scss index e23efffc0eb4da..db7e48edcd73d8 100644 --- a/packages/block-library/src/image/editor.scss +++ b/packages/block-library/src/image/editor.scss @@ -1,10 +1,6 @@ .wp-block-image { position: relative; - // This resets the intrinsic margin on the figure in non-floated, wide, and full-wide alignments. - margin-left: 0; - margin-right: 0; - &.is-transient img { opacity: 0.3; } @@ -21,6 +17,19 @@ margin-top: -9px; margin-left: -9px; } + + // These need specificity to override an inherited left/right block margin in the editor. + &.wp-block-image.alignleft { + margin-right: 1em; + margin-top: 0.5em; + margin-bottom: 0.5em; + } + + &.wp-block-image.alignright { + margin-left: 1em; + margin-top: 0.5em; + margin-bottom: 0.5em; + } } // This is necessary for the editor resize handles to accurately work on a non-floated, non-resized, small image. diff --git a/packages/block-library/src/image/style.scss b/packages/block-library/src/image/style.scss index 98620035a445e3..7ad122489aeac9 100644 --- a/packages/block-library/src/image/style.scss +++ b/packages/block-library/src/image/style.scss @@ -39,6 +39,8 @@ float: left; /*rtl:ignore*/ margin-right: 1em; + margin-top: 0.5em; + margin-bottom: 0.5em; } .alignright { @@ -46,6 +48,8 @@ float: right; /*rtl:ignore*/ margin-left: 1em; + margin-top: 0.5em; + margin-bottom: 0.5em; } .aligncenter { diff --git a/packages/block-library/src/index.native.js b/packages/block-library/src/index.native.js index aaa2305a9fdc83..6f6c5049eb7662 100644 --- a/packages/block-library/src/index.native.js +++ b/packages/block-library/src/index.native.js @@ -50,6 +50,7 @@ import * as verse from './verse'; import * as video from './video'; import * as tagCloud from './tag-cloud'; import * as group from './group'; +import * as buttons from './buttons'; export const coreBlocks = [ // Common blocks are grouped at the top to prioritize their display @@ -96,6 +97,7 @@ export const coreBlocks = [ textColumns, verse, video, + buttons, ].reduce( ( accumulator, block ) => { accumulator[ block.name ] = block; return accumulator; @@ -148,13 +150,17 @@ export const registerCoreBlocks = () => { mediaText, preformatted, gallery, + columns, + column, group, button, spacer, shortcode, + buttons, latestPosts, devOnly( verse ), - devOnly( cover ), + cover, + devOnly( pullquote ), ].forEach( registerBlock ); setDefaultBlockName( paragraph.name ); diff --git a/packages/block-library/src/latest-comments/index.js b/packages/block-library/src/latest-comments/index.js index f8516e59567a59..f3d3a8346baf3f 100644 --- a/packages/block-library/src/latest-comments/index.js +++ b/packages/block-library/src/latest-comments/index.js @@ -21,5 +21,6 @@ export const settings = { align: true, html: false, }, + example: {}, edit, }; diff --git a/packages/block-library/src/latest-posts/block.json b/packages/block-library/src/latest-posts/block.json index e730d861626502..96285d1f2705ef 100644 --- a/packages/block-library/src/latest-posts/block.json +++ b/packages/block-library/src/latest-posts/block.json @@ -10,7 +10,10 @@ "type": "string" }, "categories": { - "type": "array" + "type": "array", + "items": { + "type": "object" + } }, "postsToShow": { "type": "number", diff --git a/packages/block-library/src/latest-posts/deprecated.js b/packages/block-library/src/latest-posts/deprecated.js new file mode 100644 index 00000000000000..d49b8abab56c08 --- /dev/null +++ b/packages/block-library/src/latest-posts/deprecated.js @@ -0,0 +1,31 @@ +/** + * Internal dependencies + */ +import metadata from './block.json'; + +const { attributes } = metadata; + +export default [ + { + attributes: { + ...attributes, + categories: { + type: 'string', + }, + }, + supports: { + align: true, + html: false, + }, + migrate: ( oldAttributes ) => { + // This needs the full category object, not just the ID. + return { + ...oldAttributes, + categories: [ { id: Number( oldAttributes.categories ) } ], + }; + }, + isEligible: ( { categories } ) => + categories && 'string' === typeof categories, + save: () => null, + }, +]; diff --git a/packages/block-library/src/latest-posts/edit.js b/packages/block-library/src/latest-posts/edit.js index 81a1b9f86537d2..9f21499510367f 100644 --- a/packages/block-library/src/latest-posts/edit.js +++ b/packages/block-library/src/latest-posts/edit.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { get, invoke, isUndefined, pickBy } from 'lodash'; +import { get, includes, invoke, isUndefined, pickBy } from 'lodash'; import classnames from 'classnames'; /** @@ -104,13 +104,6 @@ class LatestPostsEdit extends Component { featuredImageSizeWidth, featuredImageSizeHeight, } = attributes; - const suggestions = categoriesList.reduce( - ( accumulator, category ) => ( { - ...accumulator, - [ category.name ]: category, - } ), - {} - ); const categorySuggestions = categoriesList.reduce( ( accumulator, category ) => ( { ...accumulator, @@ -119,11 +112,25 @@ class LatestPostsEdit extends Component { {} ); const selectCategories = ( tokens ) => { + const hasNoSuggestion = tokens.some( + ( token ) => + typeof token === 'string' && ! categorySuggestions[ token ] + ); + if ( hasNoSuggestion ) { + return; + } // Categories that are already will be objects, while new additions will be strings (the name). // allCategories nomalizes the array so that they are all objects. - const allCategories = tokens.map( ( token ) => - typeof token === 'string' ? suggestions[ token ] : token - ); + const allCategories = tokens.map( ( token ) => { + return typeof token === 'string' + ? categorySuggestions[ token ] + : token; + } ); + // We do nothing if the category is not selected + // from suggestions. + if ( includes( allCategories, null ) ) { + return false; + } setAttributes( { categories: allCategories } ); }; @@ -352,20 +359,30 @@ class LatestPostsEdit extends Component { [ `align${ featuredImageAlign }` ]: !! featuredImageAlign, } ); - const postExcerpt = + const needsReadMore = excerptLength < excerpt.trim().split( ' ' ).length && - post.excerpt.raw === '' - ? excerpt - .trim() - .split( ' ', excerptLength ) - .join( ' ' ) + - ' ... <a href="' + - post.link + - '" target="_blank" rel="noopener noreferrer">' + - __( 'Read more' ) + - '</a>' - : excerpt; + post.excerpt.raw === ''; + + const postExcerpt = needsReadMore ? ( + <> + { excerpt + .trim() + .split( ' ', excerptLength ) + .join( ' ' ) } + { /* translators: excerpt truncation character, default … */ } + { __( ' … ' ) } + <a + href={ post.link } + target="_blank" + rel="noopener noreferrer" + > + { __( 'Read more' ) } + </a> + </> + ) : ( + excerpt + ); return ( <li key={ i }> @@ -411,9 +428,7 @@ class LatestPostsEdit extends Component { { displayPostContent && displayPostContentRadio === 'excerpt' && ( <div className="wp-block-latest-posts__post-excerpt"> - <RawHTML key="html"> - { postExcerpt } - </RawHTML> + { postExcerpt } </div> ) } { displayPostContent && @@ -464,8 +479,16 @@ export default withSelect( ( select, props ) => { .map( ( { name, slug } ) => ( { value: slug, label: name } ) ); return { - defaultImageWidth: imageDimensions[ featuredImageSizeSlug ].width, - defaultImageHeight: imageDimensions[ featuredImageSizeSlug ].height, + defaultImageWidth: get( + imageDimensions, + [ featuredImageSizeSlug, 'width' ], + 0 + ), + defaultImageHeight: get( + imageDimensions, + [ featuredImageSizeSlug, 'height' ], + 0 + ), imageSizeOptions, latestPosts: ! Array.isArray( posts ) ? posts diff --git a/packages/block-library/src/latest-posts/edit.native.js b/packages/block-library/src/latest-posts/edit.native.js index f661caf1c492af..37af86b2036a3f 100644 --- a/packages/block-library/src/latest-posts/edit.native.js +++ b/packages/block-library/src/latest-posts/edit.native.js @@ -14,7 +14,7 @@ import { coreBlocks } from '@wordpress/block-library'; import { __ } from '@wordpress/i18n'; import { postList as icon } from '@wordpress/icons'; import { InspectorControls } from '@wordpress/block-editor'; -import { fetchRequest } from '@wordpress/react-native-bridge'; +import apiFetch from '@wordpress/api-fetch'; import { Icon, PanelBody, @@ -52,23 +52,13 @@ class LatestPostsEdit extends Component { componentDidMount() { this.isStillMounted = true; - this.fetchRequest = fetchRequest( '/wp/v2/categories' ) + this.fetchRequest = apiFetch( { path: '/wp/v2/categories' } ) .then( ( categoriesList ) => { if ( this.isStillMounted ) { - let parsedCategoriesList = categoriesList; - - // TODO: remove this check after `fetchRequest` types are made consist across platforms - // (see: https://github.com/wordpress-mobile/gutenberg-mobile/issues/1961) - if ( typeof categoriesList === 'string' ) { - parsedCategoriesList = JSON.parse( categoriesList ); - } - - if ( isEmpty( parsedCategoriesList ) ) { - parsedCategoriesList = []; - } - this.setState( { - categoriesList: parsedCategoriesList, + categoriesList: isEmpty( categoriesList ) + ? [] + : categoriesList, } ); } } ) @@ -195,7 +185,10 @@ class LatestPostsEdit extends Component { } onOrderChange={ this.onSetOrder } onOrderByChange={ this.onSetOrderBy } - onCategoryChange={ this.onSetCategories } + onCategoryChange={ + // eslint-disable-next-line no-undef + __DEV__ ? this.onSetCategories : undefined + } onNumberOfItemsChange={ this.onSetPostsToShow } /> </PanelBody> diff --git a/packages/block-library/src/latest-posts/index.js b/packages/block-library/src/latest-posts/index.js index 63f7b7bfae638a..cd337692eb40da 100644 --- a/packages/block-library/src/latest-posts/index.js +++ b/packages/block-library/src/latest-posts/index.js @@ -7,6 +7,7 @@ import { postList as icon } from '@wordpress/icons'; /** * Internal dependencies */ +import deprecated from './deprecated'; import edit from './edit'; import metadata from './block.json'; @@ -22,5 +23,7 @@ export const settings = { align: true, html: false, }, + example: {}, edit, + deprecated, }; diff --git a/packages/block-library/src/latest-posts/index.php b/packages/block-library/src/latest-posts/index.php index 2245ae53930af1..ea35484569e02a 100644 --- a/packages/block-library/src/latest-posts/index.php +++ b/packages/block-library/src/latest-posts/index.php @@ -33,7 +33,7 @@ function block_core_latest_posts_get_excerpt_length() { * @return string Returns the post content with latest posts added. */ function render_block_core_latest_posts( $attributes ) { - global $block_core_latest_posts_excerpt_length; + global $post, $block_core_latest_posts_excerpt_length; $args = array( 'posts_per_page' => $attributes['postsToShow'], @@ -55,6 +55,7 @@ function render_block_core_latest_posts( $attributes ) { $list_items_markup = ''; foreach ( $recent_posts as $post ) { + $list_items_markup .= '<li>'; if ( $attributes['displayFeaturedImage'] && has_post_thumbnail( $post ) ) { @@ -108,21 +109,9 @@ function render_block_core_latest_posts( $attributes ) { $trimmed_excerpt = get_the_excerpt( $post ); $list_items_markup .= sprintf( - '<div class="wp-block-latest-posts__post-excerpt">%1$s', + '<div class="wp-block-latest-posts__post-excerpt">%1$s</div>', $trimmed_excerpt ); - - if ( strpos( $trimmed_excerpt, ' &hellip; ' ) !== false ) { - $list_items_markup .= sprintf( - '<a href="%1$s">%2$s</a></div>', - esc_url( get_permalink( $post ) ), - __( 'Read more' ) - ); - } else { - $list_items_markup .= sprintf( - '</div>' - ); - } } if ( isset( $attributes['displayPostContent'] ) && $attributes['displayPostContent'] @@ -184,3 +173,34 @@ function register_block_core_latest_posts() { ); } add_action( 'init', 'register_block_core_latest_posts' ); + +/** + * Handles outdated versions of the `core/latest-posts` block by converting + * attribute `categories` from a numeric string to an array with key `id`. + * + * This is done to accommodate the changes introduced in #20781 that sought to + * add support for multiple categories to the block. However, given that this + * block is dynamic, the usual provisions for block migration are insufficient, + * as they only act when a block is loaded in the editor. + * + * TODO: Remove when and if the bottom client-side deprecation for this block + * is removed. + * + * @param array $block A single parsed block object. + * + * @return array The migrated block object. + */ +function block_core_latest_posts_migrate_categories( $block ) { + if ( + 'core/latest-posts' === $block['blockName'] && + ! empty( $block['attrs']['categories'] ) && + is_string( $block['attrs']['categories'] ) + ) { + $block['attrs']['categories'] = array( + array( 'id' => absint( $block['attrs']['categories'] ) ), + ); + } + + return $block; +} +add_filter( 'render_block_data', 'block_core_latest_posts_migrate_categories' ); diff --git a/packages/block-library/src/latest-posts/style.native.scss b/packages/block-library/src/latest-posts/style.native.scss index cba3877e8904b5..529c52f507fecf 100644 --- a/packages/block-library/src/latest-posts/style.native.scss +++ b/packages/block-library/src/latest-posts/style.native.scss @@ -31,7 +31,7 @@ text-align: center; margin-top: 8; font-size: 14; - color: #2e4453; + color: $gray-dark; } .latestPostBlockMessageDark { diff --git a/packages/block-library/src/legacy-widget/editor.scss b/packages/block-library/src/legacy-widget/editor.scss index 2d5539be15112c..6e1fac7167bd3b 100644 --- a/packages/block-library/src/legacy-widget/editor.scss +++ b/packages/block-library/src/legacy-widget/editor.scss @@ -10,6 +10,10 @@ display: block; box-shadow: none; } + // Reset z-index set on https://github.com/WordPress/wordpress-develop/commit/f26d4d37351a55fd1fc5dad0f5fef8f0f964908c. + .widget.open { + z-index: 0; + } } .wp-block-legacy-widget__update-button { diff --git a/packages/block-library/src/media-text/block.json b/packages/block-library/src/media-text/block.json index eb16cddf7d6a64..44cca8579e99c9 100644 --- a/packages/block-library/src/media-text/block.json +++ b/packages/block-library/src/media-text/block.json @@ -6,12 +6,6 @@ "type": "string", "default": "wide" }, - "backgroundColor": { - "type": "string" - }, - "customBackgroundColor": { - "type": "string" - }, "mediaAlt": { "type": "string", "source": "attribute", diff --git a/packages/block-library/src/media-text/deprecated.js b/packages/block-library/src/media-text/deprecated.js index 83512f4ee163fb..cd06840df83df6 100644 --- a/packages/block-library/src/media-text/deprecated.js +++ b/packages/block-library/src/media-text/deprecated.js @@ -2,7 +2,7 @@ * External dependencies */ import classnames from 'classnames'; -import { noop } from 'lodash'; +import { noop, isEmpty, omit } from 'lodash'; /** * WordPress dependencies @@ -16,6 +16,21 @@ import { imageFillStyles } from './media-container'; const DEFAULT_MEDIA_WIDTH = 50; +const migrateCustomColors = ( attributes ) => { + if ( ! attributes.customBackgroundColor ) { + return attributes; + } + const style = { + color: { + background: attributes.customBackgroundColor, + }, + }; + return { + ...omit( attributes, [ 'customBackgroundColor' ] ), + style, + }; +}; + const baseAttributes = { align: { type: 'string', @@ -24,9 +39,6 @@ const baseAttributes = { backgroundColor: { type: 'string', }, - customBackgroundColor: { - type: 'string', - }, mediaAlt: { type: 'string', source: 'attribute', @@ -41,12 +53,6 @@ const baseAttributes = { mediaId: { type: 'number', }, - mediaUrl: { - type: 'string', - source: 'attribute', - selector: 'figure video,figure img', - attribute: 'src', - }, mediaType: { type: 'string', }, @@ -64,6 +70,39 @@ export default [ { attributes: { ...baseAttributes, + customBackgroundColor: { + type: 'string', + }, + mediaLink: { + type: 'string', + }, + linkDestination: { + type: 'string', + }, + linkTarget: { + type: 'string', + source: 'attribute', + selector: 'figure a', + attribute: 'target', + }, + href: { + type: 'string', + source: 'attribute', + selector: 'figure a', + attribute: 'href', + }, + rel: { + type: 'string', + source: 'attribute', + selector: 'figure a', + attribute: 'rel', + }, + linkClass: { + type: 'string', + source: 'attribute', + selector: 'figure a', + attribute: 'class', + }, verticalAlignment: { type: 'string', }, @@ -74,6 +113,124 @@ export default [ type: 'object', }, }, + migrate: migrateCustomColors, + save( { attributes } ) { + const { + backgroundColor, + customBackgroundColor, + isStackedOnMobile, + mediaAlt, + mediaPosition, + mediaType, + mediaUrl, + mediaWidth, + mediaId, + verticalAlignment, + imageFill, + focalPoint, + linkClass, + href, + linkTarget, + rel, + } = attributes; + const newRel = isEmpty( rel ) ? undefined : rel; + + let image = ( + <img + src={ mediaUrl } + alt={ mediaAlt } + className={ + mediaId && mediaType === 'image' + ? `wp-image-${ mediaId }` + : null + } + /> + ); + + if ( href ) { + image = ( + <a + className={ linkClass } + href={ href } + target={ linkTarget } + rel={ newRel } + > + { image } + </a> + ); + } + + const mediaTypeRenders = { + image: () => image, + video: () => <video controls src={ mediaUrl } />, + }; + const backgroundClass = getColorClassName( + 'background-color', + backgroundColor + ); + const className = classnames( { + 'has-media-on-the-right': 'right' === mediaPosition, + 'has-background': backgroundClass || customBackgroundColor, + [ backgroundClass ]: backgroundClass, + 'is-stacked-on-mobile': isStackedOnMobile, + [ `is-vertically-aligned-${ verticalAlignment }` ]: verticalAlignment, + 'is-image-fill': imageFill, + } ); + const backgroundStyles = imageFill + ? imageFillStyles( mediaUrl, focalPoint ) + : {}; + + let gridTemplateColumns; + if ( mediaWidth !== DEFAULT_MEDIA_WIDTH ) { + gridTemplateColumns = + 'right' === mediaPosition + ? `auto ${ mediaWidth }%` + : `${ mediaWidth }% auto`; + } + const style = { + backgroundColor: backgroundClass + ? undefined + : customBackgroundColor, + gridTemplateColumns, + }; + return ( + <div className={ className } style={ style }> + <figure + className="wp-block-media-text__media" + style={ backgroundStyles } + > + { ( mediaTypeRenders[ mediaType ] || noop )() } + </figure> + <div className="wp-block-media-text__content"> + <InnerBlocks.Content /> + </div> + </div> + ); + }, + }, + { + attributes: { + ...baseAttributes, + customBackgroundColor: { + type: 'string', + }, + mediaUrl: { + type: 'string', + source: 'attribute', + selector: 'figure video,figure img', + attribute: 'src', + }, + verticalAlignment: { + type: 'string', + }, + imageFill: { + type: 'boolean', + }, + focalPoint: { + type: 'object', + }, + }, + migrate: migrateCustomColors, save( { attributes } ) { const { backgroundColor, @@ -147,7 +304,18 @@ export default [ }, }, { - attributes: baseAttributes, + attributes: { + ...baseAttributes, + customBackgroundColor: { + type: 'string', + }, + mediaUrl: { + type: 'string', + source: 'attribute', + selector: 'figure video,figure img', + attribute: 'src', + }, + }, save( { attributes } ) { const { backgroundColor, diff --git a/packages/block-library/src/media-text/edit.js b/packages/block-library/src/media-text/edit.js index 03a767862f1be4..86fd9c808596ce 100644 --- a/packages/block-library/src/media-text/edit.js +++ b/packages/block-library/src/media-text/edit.js @@ -15,8 +15,6 @@ import { BlockVerticalAlignmentToolbar, InnerBlocks, InspectorControls, - PanelColorSettings, - withColors, __experimentalImageURLInputUI as ImageURLInputUI, } from '@wordpress/block-editor'; import { Component } from '@wordpress/element'; @@ -183,10 +181,8 @@ class MediaTextEdit extends Component { const { attributes, className, - backgroundColor, isSelected, setAttributes, - setBackgroundColor, image, } = this.props; const { @@ -210,8 +206,6 @@ class MediaTextEdit extends Component { const classNames = classnames( className, { 'has-media-on-the-right': 'right' === mediaPosition, 'is-selected': isSelected, - 'has-background': backgroundColor.class || backgroundColor.color, - [ backgroundColor.class ]: backgroundColor.class, 'is-stacked-on-mobile': isStackedOnMobile, [ `is-vertically-aligned-${ verticalAlignment }` ]: verticalAlignment, 'is-image-fill': imageFill, @@ -224,15 +218,7 @@ class MediaTextEdit extends Component { const style = { gridTemplateColumns, msGridColumns: gridTemplateColumns, - backgroundColor: backgroundColor.color, }; - const colorSettings = [ - { - value: backgroundColor.color, - onChange: setBackgroundColor, - label: __( 'Background color' ), - }, - ]; const toolbarControls = [ { icon: pullLeft, @@ -311,11 +297,6 @@ class MediaTextEdit extends Component { <> <InspectorControls> { mediaTextGeneralSettings } - <PanelColorSettings - title={ __( 'Color settings' ) } - initialOpen={ false } - colorSettings={ colorSettings } - /> </InspectorControls> <BlockControls> <ToolbarGroup controls={ toolbarControls } /> @@ -352,7 +333,6 @@ class MediaTextEdit extends Component { } export default compose( [ - withColors( 'backgroundColor' ), withSelect( ( select, props ) => { const { getMedia } = select( 'core' ); const { diff --git a/packages/block-library/src/media-text/edit.native.js b/packages/block-library/src/media-text/edit.native.js index 3a582686c7c7b6..d2c70814cd5f7b 100644 --- a/packages/block-library/src/media-text/edit.native.js +++ b/packages/block-library/src/media-text/edit.native.js @@ -184,14 +184,13 @@ class MediaTextEdit extends Component { backgroundColor, setAttributes, isSelected, - isParentSelected, - isAncestorSelected, } = this.props; const { isStackedOnMobile, mediaPosition, mediaWidth, verticalAlignment, + style, } = attributes; const { containerWidth } = this.state; @@ -202,11 +201,14 @@ class MediaTextEdit extends Component { : this.state.mediaWidth || mediaWidth; const widthString = `${ temporaryMediaWidth }%`; - const innerBlockContainerStyle = ! shouldStack && { - ...styles.paddingHorizontalNone, - ...( mediaPosition === 'right' && styles.innerPaddingMediaOnRight ), - ...( mediaPosition === 'left' && styles.innerPaddingMediaOnLeft ), - }; + const innerBlockContainerStyle = ! shouldStack + ? styles.innerBlock + : { + ...( mediaPosition === 'left' + ? styles.innerBlockStackMediaLeft + : styles.innerBlockStackMediaRight ), + }; + const containerStyles = { ...styles[ 'wp-block-media-text' ], ...styles[ @@ -215,20 +217,28 @@ class MediaTextEdit extends Component { ...( mediaPosition === 'right' ? styles[ 'has-media-on-the-right' ] : {} ), - ...( shouldStack ? styles[ 'is-stacked-on-mobile' ] : {} ), + ...( shouldStack && styles[ 'is-stacked-on-mobile' ] ), ...( shouldStack && mediaPosition === 'right' ? styles[ 'is-stacked-on-mobile.has-media-on-the-right' ] : {} ), - backgroundColor: backgroundColor.color, + ...( isSelected && styles[ 'is-selected' ] ), + backgroundColor: + ( style && style.color && style.color.background ) || + backgroundColor.color, }; + const innerBlockWidth = shouldStack ? 100 : 100 - temporaryMediaWidth; const innerBlockWidthString = `${ innerBlockWidth }%`; - const mediaContainerStyle = { - ...( isParentSelected || isAncestorSelected - ? styles.denseMediaPadding - : styles.regularMediaPadding ), - ...( isSelected && styles.innerPadding ), - }; + + const mediaContainerStyle = shouldStack + ? { + ...( mediaPosition === 'left' && styles.mediaStackLeft ), + ...( mediaPosition === 'right' && styles.mediaStackRight ), + } + : { + ...( mediaPosition === 'left' && styles.mediaLeft ), + ...( mediaPosition === 'right' && styles.mediaRight ), + }; const toolbarControls = [ { @@ -256,7 +266,6 @@ class MediaTextEdit extends Component { <BlockVerticalAlignmentToolbar onChange={ onVerticalAlignmentChange } value={ verticalAlignment } - isCollapsed={ false } /> </BlockControls> <View diff --git a/packages/block-library/src/media-text/editor.scss b/packages/block-library/src/media-text/editor.scss index 115fdfc564d34a..785966ae363d3d 100644 --- a/packages/block-library/src/media-text/editor.scss +++ b/packages/block-library/src/media-text/editor.scss @@ -42,7 +42,7 @@ grid-row: 1; } -.wp-block-media-text .block-editor-inner-blocks { +.wp-block-media-text > .block-editor-inner-blocks { word-break: break-word; grid-column: 2; grid-row: 1; diff --git a/packages/block-library/src/media-text/index.js b/packages/block-library/src/media-text/index.js index 97996b6a8bb5e9..db22f30b70abf0 100644 --- a/packages/block-library/src/media-text/index.js +++ b/packages/block-library/src/media-text/index.js @@ -25,6 +25,7 @@ export const settings = { supports: { align: [ 'wide', 'full' ], html: false, + __experimentalColor: { gradients: true }, }, example: { attributes: { diff --git a/packages/block-library/src/media-text/save.js b/packages/block-library/src/media-text/save.js index 12a39e2d45f0a4..f7b676b94c18fb 100644 --- a/packages/block-library/src/media-text/save.js +++ b/packages/block-library/src/media-text/save.js @@ -7,7 +7,7 @@ import { noop, isEmpty } from 'lodash'; /** * WordPress dependencies */ -import { InnerBlocks, getColorClassName } from '@wordpress/block-editor'; +import { InnerBlocks } from '@wordpress/block-editor'; /** * Internal dependencies @@ -18,8 +18,6 @@ const DEFAULT_MEDIA_WIDTH = 50; export default function save( { attributes } ) { const { - backgroundColor, - customBackgroundColor, isStackedOnMobile, mediaAlt, mediaPosition, @@ -66,14 +64,8 @@ export default function save( { attributes } ) { image: () => image, video: () => <video controls src={ mediaUrl } />, }; - const backgroundClass = getColorClassName( - 'background-color', - backgroundColor - ); const className = classnames( { 'has-media-on-the-right': 'right' === mediaPosition, - 'has-background': backgroundClass || customBackgroundColor, - [ backgroundClass ]: backgroundClass, 'is-stacked-on-mobile': isStackedOnMobile, [ `is-vertically-aligned-${ verticalAlignment }` ]: verticalAlignment, 'is-image-fill': imageFill, @@ -90,7 +82,6 @@ export default function save( { attributes } ) { : `${ mediaWidth }% auto`; } const style = { - backgroundColor: backgroundClass ? undefined : customBackgroundColor, gridTemplateColumns, }; return ( diff --git a/packages/block-library/src/media-text/style.native.scss b/packages/block-library/src/media-text/style.native.scss index 75fb16c740df81..4e8cca364896da 100644 --- a/packages/block-library/src/media-text/style.native.scss +++ b/packages/block-library/src/media-text/style.native.scss @@ -1,3 +1,5 @@ +$media-to-text: 12px; + .wp-block-media-text { display: flex; align-items: flex-start; @@ -28,6 +30,10 @@ align-items: flex-end; } +.is-selected { + padding-bottom: 8; +} + .content { flex: 1; } @@ -104,27 +110,35 @@ color: $gray-dark; } -.innerPadding { - padding: $block-selected-to-content; +// Inner blocks STACK +.innerBlockStackMediaLeft { + margin-top: $media-to-text; +} + +.innerBlockStackMediaRight { + margin-bottom: $media-to-text; } -.innerPaddingMediaOnLeft { - padding-right: $block-selected-to-content; +// Inner blocks +.innerBlock { + padding-right: $media-to-text; + padding-left: $media-to-text; } -.innerPaddingMediaOnRight { - padding-left: $block-selected-to-content; +// Media STACK +.mediaStackLeft { + margin-bottom: $media-to-text; } -.paddingHorizontalNone { - padding-left: 0; - padding-right: 0; +.mediaStackRight { + margin-top: $media-to-text; } -.regularMediaPadding { - padding: $block-edge-to-content; +// Media +.mediaLeft { + padding-right: $media-to-text; } -.denseMediaPadding { - padding: $block-media-container-to-content; +.mediaRight { + padding-left: $media-to-text; } diff --git a/packages/block-library/src/media-text/style.scss b/packages/block-library/src/media-text/style.scss index 2a59f2cbffbecc..76549eac202696 100644 --- a/packages/block-library/src/media-text/style.scss +++ b/packages/block-library/src/media-text/style.scss @@ -65,8 +65,8 @@ /*!rtl:end:ignore*/ } -.wp-block-media-text > figure > img, -.wp-block-media-text > figure > video { +.wp-block-media-text__media img, +.wp-block-media-text__media video { max-width: unset; width: 100%; vertical-align: middle; diff --git a/packages/block-library/src/missing/edit.js b/packages/block-library/src/missing/edit.js index b9caa890a5b950..3f1d39f11edc01 100644 --- a/packages/block-library/src/missing/edit.js +++ b/packages/block-library/src/missing/edit.js @@ -17,6 +17,7 @@ function MissingBlockWarning( { attributes, convertToHTML } ) { let messageHTML; if ( hasContent && hasHTMLBlock ) { messageHTML = sprintf( + /* translators: %s: block name */ __( 'Your site doesn’t include support for the "%s" block. You can leave this block intact, convert its content to a Custom HTML block, or remove it entirely.' ), @@ -29,6 +30,7 @@ function MissingBlockWarning( { attributes, convertToHTML } ) { ); } else { messageHTML = sprintf( + /* translators: %s: block name */ __( 'Your site doesn’t include support for the "%s" block. You can leave this block intact or remove it entirely.' ), diff --git a/packages/block-library/src/missing/edit.native.js b/packages/block-library/src/missing/edit.native.js index f77e29ce9c94a3..f4072ca42000db 100644 --- a/packages/block-library/src/missing/edit.native.js +++ b/packages/block-library/src/missing/edit.native.js @@ -75,11 +75,12 @@ export class UnsupportedBlockEdit extends Component { styles.infoSheetIconDark ); - // translators: %s: Name of the block const titleFormat = Platform.OS === 'android' - ? __( "'%s' isn't yet supported on WordPress for Android" ) - : __( "'%s' isn't yet supported on WordPress for iOS" ); + ? // translators: %s: Name of the block + __( "'%s' isn't yet supported on WordPress for Android" ) + : // translators: %s: Name of the block + __( "'%s' isn't yet supported on WordPress for iOS" ); const infoTitle = sprintf( titleFormat, title ); return ( diff --git a/packages/block-library/src/navigation-link/edit.js b/packages/block-library/src/navigation-link/edit.js index c4ae29f382f770..b20ca1e528eef6 100644 --- a/packages/block-library/src/navigation-link/edit.js +++ b/packages/block-library/src/navigation-link/edit.js @@ -228,11 +228,6 @@ function NavigationLinkEdit( { 'core/strikethrough', ] } /> - { showSubmenuIcon && ( - <span className="wp-block-navigation-link__submenu-icon"> - <ItemSubmenuIcon /> - </span> - ) } { isLinkOpen && ( <Popover position="bottom center" @@ -285,6 +280,11 @@ function NavigationLinkEdit( { </Popover> ) } </div> + { showSubmenuIcon && ( + <span className="wp-block-navigation-link__submenu-icon"> + <ItemSubmenuIcon /> + </span> + ) } <InnerBlocks allowedBlocks={ [ 'core/navigation-link' ] } renderAppender={ @@ -296,7 +296,12 @@ function NavigationLinkEdit( { __experimentalTagName="ul" __experimentalAppenderTagName="li" __experimentalPassedProps={ { - className: 'wp-block-navigation__container', + className: classnames( + 'wp-block-navigation__container', + { + 'is-parent-of-selected-block': isParentOfSelectedBlock, + } + ), } } /> </Block.li> diff --git a/packages/block-library/src/navigation/edit.js b/packages/block-library/src/navigation/edit.js index 36039e879fdcee..79b610c42dfa3c 100644 --- a/packages/block-library/src/navigation/edit.js +++ b/packages/block-library/src/navigation/edit.js @@ -57,16 +57,10 @@ function Navigation( { // // HOOKS // - /* eslint-disable @wordpress/no-unused-vars-before-return */ + const ref = useRef(); const { selectBlock } = useDispatch( 'core/block-editor' ); - - const { - TextColor, - BackgroundColor, - InspectorControlsColorPanel, - ColorPanel, - } = __experimentalUseColors( + const { TextColor, BackgroundColor, ColorPanel } = __experimentalUseColors( [ { name: 'textColor', property: 'color' }, { name: 'backgroundColor', className: 'has-background' }, @@ -87,7 +81,6 @@ function Navigation( { [ fontSize.size ] ); - /* eslint-enable @wordpress/no-unused-vars-before-return */ const { navigatorToolbarButton, navigatorModal } = useBlockNavigator( clientId ); @@ -136,10 +129,6 @@ function Navigation( { const hasPages = hasResolvedPages && pages && pages.length; - const blockClassNames = classnames( className, { - [ `items-justified-${ attributes.itemsJustification }` ]: attributes.itemsJustification, - [ fontSize.class ]: fontSize.class, - } ); const blockInlineStyles = { fontSize: fontSize.size ? fontSize.size + 'px' : undefined, }; @@ -184,6 +173,12 @@ function Navigation( { ); } + const blockClassNames = classnames( className, { + [ `items-justified-${ attributes.itemsJustification }` ]: attributes.itemsJustification, + [ fontSize.class ]: fontSize.class, + 'is-vertical': attributes.orientation === 'vertical', + } ); + // UI State: rendered Block UI return ( <Fragment> @@ -243,7 +238,6 @@ function Navigation( { /> </PanelBody> </InspectorControls> - { InspectorControlsColorPanel } <InspectorControls> <PanelBody title={ __( 'Display settings' ) }> <ToggleControl @@ -270,12 +264,19 @@ function Navigation( { ref={ ref } allowedBlocks={ [ 'core/navigation-link' ] } templateInsertUpdatesSelection={ false } - __experimentalMoverDirection={ 'horizontal' } + __experimentalMoverDirection={ + attributes.orientation + } __experimentalTagName="ul" __experimentalAppenderTagName="li" __experimentalPassedProps={ { className: 'wp-block-navigation__container', } } + __experimentalCaptureToolbars={ true } + // Template lock set to false here so that the Nav + // Block on the experimental menus screen does not + // inherit templateLock={ 'all' }. + templateLock={ false } /> </Block.nav> </BackgroundColor> diff --git a/packages/block-library/src/navigation/editor.scss b/packages/block-library/src/navigation/editor.scss index f6141802433a43..4098185c23a59e 100644 --- a/packages/block-library/src/navigation/editor.scss +++ b/packages/block-library/src/navigation/editor.scss @@ -19,10 +19,20 @@ $navigation-item-height: 46px; align-items: center; } +.wp-block-navigation.is-vertical .block-list-appender { + margin: $grid-unit-10; +} + .wp-block-navigation__inserter-content { padding: $grid-unit-20; } +// Ensure sub-menus stay open and visible when a nested block is selected. +.wp-block-navigation__container.is-parent-of-selected-block { + visibility: visible; + opacity: 1; +} + /** * Colors Selector component */ diff --git a/packages/block-library/src/navigation/index.js b/packages/block-library/src/navigation/index.js index 08030d5b8895d5..db72a33515837d 100644 --- a/packages/block-library/src/navigation/index.js +++ b/packages/block-library/src/navigation/index.js @@ -32,6 +32,22 @@ export const settings = { lightBlockWrapper: true, }, + variations: [ + { + name: 'horizontal', + isDefault: true, + title: __( 'Navigation (horizontal)' ), + description: __( 'Links shown in a row.' ), + attributes: { orientation: 'horizontal' }, + }, + { + name: 'vertical', + title: __( 'Navigation (vertical)' ), + description: __( 'Links shown in a column.' ), + attributes: { orientation: 'vertical' }, + }, + ], + example: { innerBlocks: [ { diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index 355aa989701cd8..e0332a5ab206d3 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -197,15 +197,23 @@ function block_core_navigation_build_html( $attributes, $block, $colors, $font_s $font_sizes['css_classes'] ); $classes[] = 'wp-block-navigation-link'; - $css_classes = trim( implode( ' ', $classes ) ); $style_attribute = ( $colors['inline_styles'] || $font_sizes['inline_styles'] ) ? sprintf( ' style="%s"', esc_attr( $colors['inline_styles'] ) . esc_attr( $font_sizes['inline_styles'] ) ) : ''; foreach ( (array) $block['innerBlocks'] as $key => $block ) { + $css_classes = trim( implode( ' ', $classes ) ); $has_submenu = count( (array) $block['innerBlocks'] ) > 0; + $is_active = ! empty( $block['attrs']['id'] ) && ( get_the_ID() === $block['attrs']['id'] ); - $html .= '<li class="' . esc_attr( $css_classes . ( $has_submenu ? ' has-child' : '' ) ) . '"' . $style_attribute . '>' . + $class_name = ! empty( $block['attrs']['className'] ) ? implode( ' ', (array) $block['attrs']['className'] ) : false; + + if ( false !== $class_name ) { + $css_classes .= ' ' . $class_name; + }; + + $html .= '<li class="' . esc_attr( $css_classes . ( $has_submenu ? ' has-child' : '' ) ) . + ( $is_active ? ' current-menu-item' : '' ) . '"' . $style_attribute . '>' . '<a class="wp-block-navigation-link__content"'; // Start appending HTML attributes to anchor tag. @@ -247,6 +255,9 @@ function block_core_navigation_build_html( $attributes, $block, $colors, $font_s $html .= '</span>'; + $html .= '</a>'; + // End anchor tag content. + // Append submenu icon to top-level item. // it shows the icon as default, when 'showSubmenuIcon' is not set, // or when it's set and also not False. @@ -260,11 +271,8 @@ function block_core_navigation_build_html( $attributes, $block, $colors, $font_s $html .= '<span class="wp-block-navigation-link__submenu-icon">' . block_core_navigation_render_submenu_icon() . '</span>'; } - $html .= '</a>'; - // End anchor tag content. - if ( $has_submenu ) { - $html .= block_core_navigation_build_html( $attributes, $block, $colors, $font_sizes, false ); + $html .= block_core_navigation_build_html( $attributes, $block, $colors, $font_sizes ); } $html .= '</li>'; @@ -284,6 +292,9 @@ function register_block_core_navigation() { 'core/navigation', array( 'attributes' => array( + 'orientation' => array( + 'type' => 'string', + ), 'className' => array( 'type' => 'string', ), diff --git a/packages/block-library/src/navigation/style.scss b/packages/block-library/src/navigation/style.scss index c595f75f198d14..3c7488427ed76a 100644 --- a/packages/block-library/src/navigation/style.scss +++ b/packages/block-library/src/navigation/style.scss @@ -1,268 +1,133 @@ -$navigation-menu-height: $grid-unit-10 * 7; -$navigation-sub-menu-height: $grid-unit-10 * 5; -$navigation-sub-menu-width: $grid-unit-10 * 25; - -/* -* Frontend: reset the default list styles -*/ - -.wp-block-navigation > ul { - display: block; +.wp-block-navigation__container { + // Reset the default list styles list-style: none; margin: 0; padding-left: 0; - @include break-small { - display: flex; - flex-wrap: wrap; - } + // Horizontal layout + display: flex; + flex-wrap: wrap; - // Submenu - ul { - list-style: none; - padding-left: 0; - margin-top: 0; - margin-left: 0; + // Vertical layout - li { - margin: 0; - } + .is-vertical & { + display: block; } } -/* -* Frontend: styles for submenu flyout -*/ - -.wp-block-navigation > ul { - li { - z-index: 1; - - &:hover, - &:focus-within { - cursor: pointer; - z-index: 99999; - } - - // Submenu Display - &:hover > ul, - &:focus-within > ul, - & ul:hover, - & ul:focus { - visibility: visible; - opacity: 1; - display: flex; - flex-direction: column; - } - } +.wp-block-navigation-link { + display: flex; + align-items: center; + position: relative; + margin: 0; + padding: $grid-unit-10; +} - & > li ul { +// Styles for submenu flyout +.has-child { + .wp-block-navigation__container { + border: $border-width solid rgba(0, 0, 0, 0.15); + padding: $grid-unit-10 * 0.75 $grid-unit-10 * 2; + background-color: inherit; + color: inherit; position: absolute; left: 0; top: 100%; - min-width: $navigation-sub-menu-width; - max-width: $navigation-sub-menu-width; + z-index: 1; opacity: 0; transition: opacity 0.1s linear; visibility: hidden; - } -} -/* -* Styles shared between editor and frontend -*/ -.wp-block-navigation, -.wp-block-navigation .block-editor-block-list__layout { - display: flex; - flex-wrap: wrap; -} - -.wp-block-navigation { - - // set a width on the editor submenus - .block-editor-block-list__layout .block-editor-block-list__layout { - width: $navigation-sub-menu-width; - } - - &, - > .wp-block-navigation__container { - align-items: center; - width: 100%; - - > .wp-block-navigation-link { - display: flex; - margin-top: 0; - margin-bottom: 0; - } - } - - // Main menu - .wp-block-navigation-link { - position: relative; - margin: 0; - min-height: $navigation-menu-height; - display: flex; - line-height: 1.4; - - // Sub menus - .wp-block, - .wp-block-navigation-link { - min-height: auto; // reset the min-height and rely on padding - padding: 0; - } - - // Sub menus (editor canvas) - .wp-block .wp-block-navigation-link { - margin: 0; - } - - &.has-child > .wp-block-navigation__container { - // Box model - display: flex; - border: $border-width solid rgba(0, 0, 0, 0.15); - - // Position (first level) - position: absolute; - z-index: 1; - top: 100%; - left: 0; // just under the main menu item. - - // Position (nested levels) - .block-editor-inner-blocks, + // Nested submenus sit to the left on large breakpoints + @include break-medium { .wp-block-navigation__container { left: 100%; - top: - $border-width; + top: -$border-width; } } + } + // Separating out hover and focus-within so hover works again on IE: https://davidwalsh.name/css-focus-within#comment-513401 + // We will need to replace focus-within with a JS solution for IE keyboard support. + &:hover { + cursor: pointer; - // Inherit colors from menu - .wp-block-navigation__container { - background-color: inherit; - color: inherit; - } - - // All links - .wp-block-navigation-link__content { + > .wp-block-navigation__container { + visibility: visible; + opacity: 1; display: flex; - align-items: center; - width: max-content; - padding: $grid-unit-10 * 0.75 $grid-unit-10 * 2; - } - - // Submenu links only - .wp-block-navigation-link { - - &:first-child:not(:only-child) .wp-block-navigation-link__content { - padding-top: $grid-unit-10; - } - - &:last-child .wp-block-navigation-link__content { - padding-bottom: $grid-unit-10; - } - } - - &.has-child .wp-block-navigation-link__content { - min-width: 100%; - padding-right: $grid-unit-10 * 4; - position: relative; + flex-direction: column; } + } - .wp-block-navigation-link__submenu-icon { - position: absolute; - right: $grid-unit-10 * 2; + &:focus-within { + cursor: pointer; - svg { - fill: currentColor; - } + > .wp-block-navigation__container { + visibility: visible; + opacity: 1; + display: flex; + flex-direction: column; } + } +} - // reset rotation of submenu indicator icons on nested levels - .wp-block-navigation-link svg { - transform: rotate(0); - } +// All links +.wp-block-navigation-link__content { + padding: $grid-unit-10 * 0.75 $grid-unit-10 * 2; - &.has-text-color .wp-block-navigation-link__content { - color: inherit; - } + .has-text-color & { + color: inherit; } } -// Styles -.wp-block-navigation { - - // Default / Light styles - .wp-block-navigation-link, - &.is-style-light .wp-block-navigation-link { - // No text color - &:not(.has-text-color) > .wp-block-navigation__container { - color: $light-style-sub-menu-text-color; - } +.wp-block-navigation-link__label { + word-break: normal; + overflow-wrap: break-word; +} - // No background color - &:not(.has-background) > .wp-block-navigation__container { - background-color: $light-style-sub-menu-background-color; - } - } +.wp-block-navigation-link__submenu-icon { + padding: $grid-unit-10 * 0.75 $grid-unit-10 * 2; - // Dark styles. - &.is-style-dark .wp-block-navigation-link { - // No text color - &:not(.has-text-color) > .wp-block-navigation__container { - color: $dark-style-sub-menu-text-color; - } + svg { + fill: currentColor; - // No background color - &:not(.has-background) > .wp-block-navigation__container { - background-color: $dark-style-sub-menu-background-color; + @include break-medium { + // reset rotation of submenu indicator icons on nested levels + transform: rotate(0); } } } -/* -* Frontend: non-shared styles & overrides -*/ - -.wp-block-navigation { - - .wp-block-navigation-link.has-child > .wp-block-navigation__container { - display: flex; - flex-direction: column; - padding: 0; +// Default / Light styles +.wp-block-navigation-link, +.is-style-light .wp-block-navigation-link { + &:not(.has-text-color) .wp-block-navigation-link__content { + color: $light-style-sub-menu-text-color; } } +.is-style-light:not(.has-background) .wp-block-navigation__container { + background-color: $light-style-sub-menu-background-color; +} -/* -* TODO: organize/untangle styles below this line -*/ - -.wp-block-navigation { - - & > ul { - & > li { - & > a { - display: flex; - align-items: center; - } - - &:first-of-type > a { - padding-left: 0; - } - - &:last-of-type > a { - padding-right: 0; - } - } +// Dark styles. +.is-style-dark .wp-block-navigation-link { + &:not(.has-text-color) .wp-block-navigation-link__content { + color: $dark-style-sub-menu-text-color; } +} +.is-style-dark:not(.has-background) .wp-block-navigation__container { + background-color: $dark-style-sub-menu-background-color; +} - &.items-justified-left > ul { - justify-content: flex-start; - } +// Jutification. +.items-justified-left > ul { + justify-content: flex-start; +} - &.items-justified-center > ul { - justify-content: center; - } +.items-justified-center > ul { + justify-content: center; +} - &.items-justified-right > ul { - justify-content: flex-end; - } +.items-justified-right > ul { + justify-content: flex-end; } diff --git a/packages/block-library/src/navigation/theme.scss b/packages/block-library/src/navigation/theme.scss index 0b80d85004697a..d628390770ebbc 100644 --- a/packages/block-library/src/navigation/theme.scss +++ b/packages/block-library/src/navigation/theme.scss @@ -4,3 +4,8 @@ list-style: none; } } + +// Overrides generic ".entry-content li" styles on the front end. +.wp-block-navigation-link.wp-block-navigation-link { + margin: 0; +} diff --git a/packages/block-library/src/paragraph/block.json b/packages/block-library/src/paragraph/block.json index 4f1d668b7c4d5c..acd5e48f0f63e0 100644 --- a/packages/block-library/src/paragraph/block.json +++ b/packages/block-library/src/paragraph/block.json @@ -18,27 +18,12 @@ "placeholder": { "type": "string" }, - "textColor": { - "type": "string" - }, - "customTextColor": { - "type": "string" - }, - "backgroundColor": { - "type": "string" - }, - "customBackgroundColor": { - "type": "string" - }, - "fontSize": { - "type": "string" - }, - "customFontSize": { - "type": "number" - }, "direction": { "type": "string", - "enum": [ "ltr", "rtl" ] + "enum": [ + "ltr", + "rtl" + ] } } } diff --git a/packages/block-library/src/paragraph/deprecated.js b/packages/block-library/src/paragraph/deprecated.js index 8c0502d808079f..24896a034207d0 100644 --- a/packages/block-library/src/paragraph/deprecated.js +++ b/packages/block-library/src/paragraph/deprecated.js @@ -38,31 +38,133 @@ const blockAttributes = { textColor: { type: 'string', }, - customTextColor: { - type: 'string', - }, backgroundColor: { type: 'string', }, - customBackgroundColor: { - type: 'string', - }, fontSize: { type: 'string', }, - customFontSize: { - type: 'number', - }, direction: { type: 'string', enum: [ 'ltr', 'rtl' ], }, + style: { + type: 'object', + }, +}; + +const migrateCustomColorsAndFontSizes = ( attributes ) => { + if ( + ! attributes.customTextColor && + ! attributes.customBackgroundColor && + ! attributes.customFontSize + ) { + return attributes; + } + const style = {}; + if ( attributes.customTextColor || attributes.customBackgroundColor ) { + style.color = {}; + } + if ( attributes.customTextColor ) { + style.color.text = attributes.customTextColor; + } + if ( attributes.customBackgroundColor ) { + style.color.background = attributes.customBackgroundColor; + } + if ( attributes.customFontSize ) { + style.typography = { fontSize: attributes.customFontSize }; + } + return { + ...omit( attributes, [ + 'customTextColor', + 'customBackgroundColor', + 'customFontSize', + ] ), + style, + }; }; const deprecated = [ { supports, - attributes: blockAttributes, + attributes: { + ...omit( blockAttributes, [ 'style' ] ), + customTextColor: { + type: 'string', + }, + customBackgroundColor: { + type: 'string', + }, + customFontSize: { + type: 'number', + }, + }, + migrate: migrateCustomColorsAndFontSizes, + save( { attributes } ) { + const { + align, + content, + dropCap, + backgroundColor, + textColor, + customBackgroundColor, + customTextColor, + fontSize, + customFontSize, + direction, + } = attributes; + + const textClass = getColorClassName( 'color', textColor ); + const backgroundClass = getColorClassName( + 'background-color', + backgroundColor + ); + const fontSizeClass = getFontSizeClass( fontSize ); + + const className = classnames( { + 'has-text-color': textColor || customTextColor, + 'has-background': backgroundColor || customBackgroundColor, + 'has-drop-cap': dropCap, + [ `has-text-align-${ align }` ]: align, + [ fontSizeClass ]: fontSizeClass, + [ textClass ]: textClass, + [ backgroundClass ]: backgroundClass, + } ); + + const styles = { + backgroundColor: backgroundClass + ? undefined + : customBackgroundColor, + color: textClass ? undefined : customTextColor, + fontSize: fontSizeClass ? undefined : customFontSize, + }; + + return ( + <RichText.Content + tagName="p" + style={ styles } + className={ className ? className : undefined } + value={ content } + dir={ direction } + /> + ); + }, + }, + { + supports, + attributes: { + ...omit( blockAttributes, [ 'style' ] ), + customTextColor: { + type: 'string', + }, + customBackgroundColor: { + type: 'string', + }, + customFontSize: { + type: 'number', + }, + }, + migrate: migrateCustomColorsAndFontSizes, save( { attributes } ) { const { align, @@ -116,11 +218,21 @@ const deprecated = [ { supports, attributes: { - ...blockAttributes, + ...omit( blockAttributes, [ 'style' ] ), + customTextColor: { + type: 'string', + }, + customBackgroundColor: { + type: 'string', + }, + customFontSize: { + type: 'number', + }, width: { type: 'string', }, }, + migrate: migrateCustomColorsAndFontSizes, save( { attributes } ) { const { width, @@ -179,9 +291,7 @@ const deprecated = [ type: 'number', }, }, - 'customFontSize', - 'customTextColor', - 'customBackgroundColor' + [ 'style' ] ), save( { attributes } ) { const { @@ -215,8 +325,8 @@ const deprecated = [ ); }, migrate( attributes ) { - return omit( - { + return migrateCustomColorsAndFontSizes( + omit( { ...attributes, customFontSize: isFinite( attributes.fontSize ) ? attributes.fontSize @@ -231,8 +341,8 @@ const deprecated = [ '#' === attributes.backgroundColor[ 0 ] ? attributes.backgroundColor : undefined, - }, - [ 'fontSize', 'textColor', 'backgroundColor' ] + } ), + [ 'fontSize', 'textColor', 'backgroundColor', 'style' ] ); }, }, diff --git a/packages/block-library/src/paragraph/edit.js b/packages/block-library/src/paragraph/edit.js index 105b1a502c763e..bcae630f0e5ac9 100644 --- a/packages/block-library/src/paragraph/edit.js +++ b/packages/block-library/src/paragraph/edit.js @@ -11,15 +11,12 @@ import { PanelBody, ToggleControl, ToolbarGroup } from '@wordpress/components'; import { AlignmentToolbar, BlockControls, - FontSizePicker, InspectorControls, RichText, - withFontSizes, - __experimentalUseColors, __experimentalBlock as Block, + getFontSize, } from '@wordpress/block-editor'; import { createBlock } from '@wordpress/blocks'; -import { compose } from '@wordpress/compose'; import { useSelect } from '@wordpress/data'; import { useEffect, useState, useRef } from '@wordpress/element'; import { formatLtr } from '@wordpress/icons'; @@ -75,39 +72,32 @@ function useDropCapMinimumHeight( isDropCap, deps ) { function ParagraphBlock( { attributes, - fontSize, mergeBlocks, onReplace, setAttributes, - setFontSize, } ) { - const { align, content, dropCap, placeholder, direction } = attributes; - + const { + align, + content, + direction, + dropCap, + placeholder, + fontSize, + style, + } = attributes; + const { fontSizes } = useSelect( ( select ) => + select( 'core/block-editor' ).getSettings() + ); const ref = useRef(); + const fontSizeObject = getFontSize( fontSizes, fontSize, style?.fontSize ); const dropCapMinimumHeight = useDropCapMinimumHeight( dropCap, [ - fontSize.size, + fontSizeObject.size, ] ); - const { - TextColor, - BackgroundColor, - InspectorControlsColorPanel, - } = __experimentalUseColors( - [ - { name: 'textColor', property: 'color' }, - { name: 'backgroundColor', className: 'has-background' }, - ], - { - contrastCheckers: [ - { - backgroundColor: true, - textColor: true, - fontSize: fontSize.size, - }, - ], - colorDetector: { targetRef: ref }, - }, - [ fontSize.size ] - ); + + const styles = { + direction, + minHeight: dropCapMinimumHeight, + }; return ( <> @@ -127,10 +117,6 @@ function ParagraphBlock( { </BlockControls> <InspectorControls> <PanelBody title={ __( 'Text settings' ) }> - <FontSizePicker - value={ fontSize.size } - onChange={ setFontSize } - /> <ToggleControl label={ __( 'Drop cap' ) } checked={ !! dropCap } @@ -145,66 +131,48 @@ function ParagraphBlock( { /> </PanelBody> </InspectorControls> - { InspectorControlsColorPanel } - <BackgroundColor> - <TextColor> - <RichText - ref={ ref } - identifier="content" - tagName={ Block.p } - className={ classnames( { - 'has-drop-cap': dropCap, - [ `has-text-align-${ align }` ]: align, - [ fontSize.class ]: fontSize.class, - } ) } - style={ { - fontSize: fontSize.size - ? fontSize.size + 'px' - : undefined, - direction, - minHeight: dropCapMinimumHeight, - } } - value={ content } - onChange={ ( newContent ) => - setAttributes( { content: newContent } ) - } - onSplit={ ( value ) => { - if ( ! value ) { - return createBlock( name ); - } + <RichText + ref={ ref } + identifier="content" + tagName={ Block.p } + className={ classnames( { + 'has-drop-cap': dropCap, + [ `has-text-align-${ align }` ]: align, + } ) } + style={ styles } + value={ content } + onChange={ ( newContent ) => + setAttributes( { content: newContent } ) + } + onSplit={ ( value ) => { + if ( ! value ) { + return createBlock( name ); + } - return createBlock( name, { - ...attributes, - content: value, - } ); - } } - onMerge={ mergeBlocks } - onReplace={ onReplace } - onRemove={ - onReplace ? () => onReplace( [] ) : undefined - } - aria-label={ - content - ? __( 'Paragraph block' ) - : __( - 'Empty block; start writing or type forward slash to choose a block' - ) - } - placeholder={ - placeholder || - __( 'Start writing or type / to choose a block' ) - } - __unstableEmbedURLOnPaste - __unstableAllowPrefixTransformations - /> - </TextColor> - </BackgroundColor> + return createBlock( name, { + ...attributes, + content: value, + } ); + } } + onMerge={ mergeBlocks } + onReplace={ onReplace } + onRemove={ onReplace ? () => onReplace( [] ) : undefined } + aria-label={ + content + ? __( 'Paragraph block' ) + : __( + 'Empty block; start writing or type forward slash to choose a block' + ) + } + placeholder={ + placeholder || + __( 'Start writing or type / to choose a block' ) + } + __unstableEmbedURLOnPaste + __unstableAllowPrefixTransformations + /> </> ); } -const ParagraphEdit = compose( [ withFontSizes( 'fontSize' ) ] )( - ParagraphBlock -); - -export default ParagraphEdit; +export default ParagraphBlock; diff --git a/packages/block-library/src/paragraph/edit.native.js b/packages/block-library/src/paragraph/edit.native.js index b02cdc3662125a..1027f46371508a 100644 --- a/packages/block-library/src/paragraph/edit.native.js +++ b/packages/block-library/src/paragraph/edit.native.js @@ -7,7 +7,6 @@ import { AlignmentToolbar, BlockControls, RichText, - __experimentalUseColors, } from '@wordpress/block-editor'; const name = 'core/paragraph'; @@ -17,56 +16,52 @@ function ParagraphBlock( { mergeBlocks, onReplace, setAttributes, - style, + style: oldStyle, } ) { - const { align, content, placeholder } = attributes; + const { align, content, placeholder, style } = attributes; - /* eslint-disable @wordpress/no-unused-vars-before-return */ - const { TextColor } = __experimentalUseColors( [ - { name: 'textColor', property: 'color' }, - ] ); - /* eslint-enable @wordpress/no-unused-vars-before-return */ + const styles = { + ...oldStyle, + color: style && style.color && style.color.text, + }; return ( <> <BlockControls> <AlignmentToolbar - isCollapsed={ false } value={ align } onChange={ ( nextAlign ) => { setAttributes( { align: nextAlign } ); } } /> </BlockControls> - <TextColor> - <RichText - identifier="content" - tagName="p" - value={ content } - deleteEnter={ true } - style={ style } - onChange={ ( nextContent ) => { - setAttributes( { - content: nextContent, - } ); - } } - onSplit={ ( value ) => { - if ( ! value ) { - return createBlock( name ); - } + <RichText + identifier="content" + tagName="p" + value={ content } + deleteEnter={ true } + style={ styles } + onChange={ ( nextContent ) => { + setAttributes( { + content: nextContent, + } ); + } } + onSplit={ ( value ) => { + if ( ! value ) { + return createBlock( name ); + } - return createBlock( name, { - ...attributes, - content: value, - } ); - } } - onMerge={ mergeBlocks } - onReplace={ onReplace } - onRemove={ onReplace ? () => onReplace( [] ) : undefined } - placeholder={ placeholder || __( 'Start writing…' ) } - textAlign={ align } - /> - </TextColor> + return createBlock( name, { + ...attributes, + content: value, + } ); + } } + onMerge={ mergeBlocks } + onReplace={ onReplace } + onRemove={ onReplace ? () => onReplace( [] ) : undefined } + placeholder={ placeholder || __( 'Start writing…' ) } + textAlign={ align } + /> </> ); } diff --git a/packages/block-library/src/paragraph/editor.scss b/packages/block-library/src/paragraph/editor.scss index 20b0f6a4311cd9..d0afb9ca839208 100644 --- a/packages/block-library/src/paragraph/editor.scss +++ b/packages/block-library/src/paragraph/editor.scss @@ -3,34 +3,6 @@ min-height: auto !important; } - -// Show a footprint fade effect when first selecting any block. -.block-editor-block-list__block[data-type="core/paragraph"].is-selected { - &::before { - position: absolute; - z-index: 1; - pointer-events: none; - content: ""; - top: 0; - bottom: 0; - left: 0; - right: 0; - animation: block-editor-block-list__block-fade-out-animation 0.3s ease-out 0.2s; - animation-fill-mode: forwards; - @include reduce-motion("animation"); - } - - // Only flash it if you're not typing. - &:not(.is-typing)::before { - background: rgba($black, 0.03); - - // Flash a white color for dark themes. - .is-dark-theme & { - background: rgba($white, 0.1); - } - } -} - @keyframes block-editor-block-list__block-fade-out-animation { from { opacity: 1; diff --git a/packages/block-library/src/paragraph/index.js b/packages/block-library/src/paragraph/index.js index 7fa310086cb459..0e76e74adc338f 100644 --- a/packages/block-library/src/paragraph/index.js +++ b/packages/block-library/src/paragraph/index.js @@ -32,7 +32,11 @@ export const settings = { content: __( 'In a village of La Mancha, the name of which I have no desire to call to mind, there lived not long since one of those gentlemen that keep a lance in the lance-rack, an old buckler, a lean hack, and a greyhound for coursing.' ), - customFontSize: 28, + style: { + typography: { + fontSize: 28, + }, + }, dropCap: true, }, }, @@ -40,6 +44,9 @@ export const settings = { className: false, __unstablePasteTextInline: true, lightBlockWrapper: true, + __experimentalColor: true, + __experimentalLineHeight: true, + __experimentalFontSize: true, }, __experimentalLabel( attributes, { context } ) { if ( context === 'accessibility' ) { diff --git a/packages/block-library/src/paragraph/save.js b/packages/block-library/src/paragraph/save.js index 2cdeeb46e60c9c..434cc022295588 100644 --- a/packages/block-library/src/paragraph/save.js +++ b/packages/block-library/src/paragraph/save.js @@ -6,53 +6,19 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import { - getColorClassName, - getFontSizeClass, - RichText, -} from '@wordpress/block-editor'; +import { RichText } from '@wordpress/block-editor'; export default function save( { attributes } ) { - const { - align, - content, - dropCap, - backgroundColor, - textColor, - customBackgroundColor, - customTextColor, - fontSize, - customFontSize, - direction, - } = attributes; - - const textClass = getColorClassName( 'color', textColor ); - const backgroundClass = getColorClassName( - 'background-color', - backgroundColor - ); - const fontSizeClass = getFontSizeClass( fontSize ); + const { align, content, dropCap, direction } = attributes; const className = classnames( { - 'has-text-color': textColor || customTextColor, - 'has-background': backgroundColor || customBackgroundColor, 'has-drop-cap': dropCap, [ `has-text-align-${ align }` ]: align, - [ fontSizeClass ]: fontSizeClass, - [ textClass ]: textClass, - [ backgroundClass ]: backgroundClass, } ); - const styles = { - backgroundColor: backgroundClass ? undefined : customBackgroundColor, - color: textClass ? undefined : customTextColor, - fontSize: fontSizeClass ? undefined : customFontSize, - }; - return ( <RichText.Content tagName="p" - style={ styles } className={ className ? className : undefined } value={ content } dir={ direction } diff --git a/packages/block-library/src/post-author/edit.js b/packages/block-library/src/post-author/edit.js index 9ca968c5679f70..05ab61f3ef92a7 100644 --- a/packages/block-library/src/post-author/edit.js +++ b/packages/block-library/src/post-author/edit.js @@ -13,7 +13,13 @@ function PostAuthorDisplay() { [ authorId ] ); return author ? ( - <address>{ sprintf( __( 'By %s' ), author.name ) }</address> + <address> + { sprintf( + /* translators: %s: author name. */ + __( 'By %s' ), + author.name + ) } + </address> ) : null; } diff --git a/packages/block-library/src/post-author/index.php b/packages/block-library/src/post-author/index.php index 6dc30ea5b4ba18..57f1895f6cb0c6 100644 --- a/packages/block-library/src/post-author/index.php +++ b/packages/block-library/src/post-author/index.php @@ -23,16 +23,10 @@ function render_block_core_post_author() { * Registers the `core/post-author` block on the server. */ function register_block_core_post_author() { - $path = __DIR__ . '/post-author/block.json'; - $metadata = json_decode( file_get_contents( $path ), true ); - - register_block_type( - $metadata['name'], - array_merge( - $metadata, - array( - 'render_callback' => 'render_block_core_post_author', - ) + register_block_type_from_metadata( + __DIR__ . '/post-author', + array( + 'render_callback' => 'render_block_core_post_author', ) ); } diff --git a/packages/block-library/src/post-comments-count/index.php b/packages/block-library/src/post-comments-count/index.php index 0c22f35068f175..a7e811b8157324 100644 --- a/packages/block-library/src/post-comments-count/index.php +++ b/packages/block-library/src/post-comments-count/index.php @@ -32,21 +32,15 @@ function render_block_core_post_comments_count( $attributes ) { * Registers the `core/post-comments-count` block on the server. */ function register_block_core_post_comments_count() { - $path = __DIR__ . '/post-comments-count/block.json'; - $metadata = json_decode( file_get_contents( $path ), true ); - - register_block_type( - $metadata['name'], - array_merge( - $metadata, - array( - 'attributes' => array( - 'className' => array( - 'type' => 'string', - ), + register_block_type_from_metadata( + __DIR__ . '/post-comments-count', + array( + 'attributes' => array( + 'className' => array( + 'type' => 'string', ), - 'render_callback' => 'render_block_core_post_comments_count', - ) + ), + 'render_callback' => 'render_block_core_post_comments_count', ) ); } diff --git a/packages/block-library/src/post-comments-form/index.php b/packages/block-library/src/post-comments-form/index.php index cb1aff17fc5af1..9d5e78cffa5cfa 100644 --- a/packages/block-library/src/post-comments-form/index.php +++ b/packages/block-library/src/post-comments-form/index.php @@ -26,16 +26,10 @@ function render_block_core_post_comments_form() { * Registers the `core/post-comments-form` block on the server. */ function register_block_core_post_comments_form() { - $path = __DIR__ . '/post-comments-form/block.json'; - $metadata = json_decode( file_get_contents( $path ), true ); - - register_block_type( - $metadata['name'], - array_merge( - $metadata, - array( - 'render_callback' => 'render_block_core_post_comments_form', - ) + register_block_type_from_metadata( + __DIR__ . '/post-comments-form', + array( + 'render_callback' => 'render_block_core_post_comments_form', ) ); } diff --git a/packages/block-library/src/post-comments/index.php b/packages/block-library/src/post-comments/index.php index d9f35117a74da3..85780230704ecd 100644 --- a/packages/block-library/src/post-comments/index.php +++ b/packages/block-library/src/post-comments/index.php @@ -15,17 +15,12 @@ function render_block_core_post_comments() { if ( ! $post ) { return ''; } - $comments = get_comments( - array( - 'post_id' => $post->ID, - ) - ); - $output = ''; - // TODO: Handle nested comments. - foreach ( $comments as $comment ) { - $output .= '<p>' . $comment->comment_author . '<br />' . $comment->comment_content . '</p>'; - } - return $output; + + // This generates a deprecate message. + // Ideally this deprecation is removed. + ob_start(); + comments_template(); + return ob_get_clean(); } /** diff --git a/packages/block-library/src/post-content/edit.js b/packages/block-library/src/post-content/edit.js index d80b308b384b16..3336e0d8199676 100644 --- a/packages/block-library/src/post-content/edit.js +++ b/packages/block-library/src/post-content/edit.js @@ -1,3 +1,9 @@ export default function PostContentEdit() { - return 'Post Content Placeholder'; + return ( + <p> + { + 'Welcome to WordPress and the wonderful world of blocks. This content represents how a post would look when editing block templates.' + } + </p> + ); } diff --git a/packages/block-library/src/post-content/index.php b/packages/block-library/src/post-content/index.php index 1e6870fd0b3134..dc7eebdf00ffa2 100644 --- a/packages/block-library/src/post-content/index.php +++ b/packages/block-library/src/post-content/index.php @@ -26,16 +26,10 @@ function render_block_core_post_content() { * Registers the `core/post-content` block on the server. */ function register_block_core_post_content() { - $path = __DIR__ . '/post-content/block.json'; - $metadata = json_decode( file_get_contents( $path ), true ); - - register_block_type( - $metadata['name'], - array_merge( - $metadata, - array( - 'render_callback' => 'render_block_core_post_content', - ) + register_block_type_from_metadata( + __DIR__ . '/post-content', + array( + 'render_callback' => 'render_block_core_post_content', ) ); } diff --git a/packages/block-library/src/post-date/edit.js b/packages/block-library/src/post-date/edit.js index 5c04fe66cbb091..fae4aceef783df 100644 --- a/packages/block-library/src/post-date/edit.js +++ b/packages/block-library/src/post-date/edit.js @@ -90,7 +90,7 @@ export default function PostDateEdit( { setAttributes, } ) { if ( ! useEntityId( 'postType', 'post' ) ) { - return 'Post Date Placeholder'; + return <p>{ 'Jan 1st, 1440' }</p>; } return <PostDateEditor format={ format } setAttributes={ setAttributes } />; } diff --git a/packages/block-library/src/post-date/index.php b/packages/block-library/src/post-date/index.php index 22e4c53e311eaf..dd86ff7e8c92ca 100644 --- a/packages/block-library/src/post-date/index.php +++ b/packages/block-library/src/post-date/index.php @@ -27,16 +27,10 @@ function render_block_core_post_date( $attributes ) { * Registers the `core/post-date` block on the server. */ function register_block_core_post_date() { - $path = __DIR__ . '/post-date/block.json'; - $metadata = json_decode( file_get_contents( $path ), true ); - - register_block_type( - $metadata['name'], - array_merge( - $metadata, - array( - 'render_callback' => 'render_block_core_post_date', - ) + register_block_type_from_metadata( + __DIR__ . '/post-date', + array( + 'render_callback' => 'render_block_core_post_date', ) ); } diff --git a/packages/block-library/src/post-excerpt/index.php b/packages/block-library/src/post-excerpt/index.php index 5d2ee7755beee4..7f5ab586670fa8 100644 --- a/packages/block-library/src/post-excerpt/index.php +++ b/packages/block-library/src/post-excerpt/index.php @@ -47,16 +47,10 @@ function render_block_core_post_excerpt( $attributes ) { * Registers the `core/post-excerpt` block on the server. */ function register_block_core_post_excerpt() { - $path = __DIR__ . '/post-excerpt/block.json'; - $metadata = json_decode( file_get_contents( $path ), true ); - - register_block_type( - $metadata['name'], - array_merge( - $metadata, - array( - 'render_callback' => 'render_block_core_post_excerpt', - ) + register_block_type_from_metadata( + __DIR__ . '/post-excerpt', + array( + 'render_callback' => 'render_block_core_post_excerpt', ) ); } diff --git a/packages/block-library/src/post-featured-image/index.php b/packages/block-library/src/post-featured-image/index.php index 4a03b2e4d30284..9a80c2525fa3ee 100644 --- a/packages/block-library/src/post-featured-image/index.php +++ b/packages/block-library/src/post-featured-image/index.php @@ -22,16 +22,10 @@ function render_block_core_post_featured_image() { * Registers the `core/post-featured-image` block on the server. */ function register_block_core_post_featured_image() { - $path = __DIR__ . '/post-featured-image/block.json'; - $metadata = json_decode( file_get_contents( $path ), true ); - - register_block_type( - $metadata['name'], - array_merge( - $metadata, - array( - 'render_callback' => 'render_block_core_post_featured_image', - ) + register_block_type_from_metadata( + __DIR__ . '/post-featured-image', + array( + 'render_callback' => 'render_block_core_post_featured_image', ) ); } diff --git a/packages/block-library/src/post-tags/index.php b/packages/block-library/src/post-tags/index.php index 4fff8d0014c840..ed03b6055f7cfa 100644 --- a/packages/block-library/src/post-tags/index.php +++ b/packages/block-library/src/post-tags/index.php @@ -29,16 +29,10 @@ function render_block_core_post_tags() { * Registers the `core/post-tags` block on the server. */ function register_block_core_post_tags() { - $path = __DIR__ . '/post-tags/block.json'; - $metadata = json_decode( file_get_contents( $path ), true ); - - register_block_type( - $metadata['name'], - array_merge( - $metadata, - array( - 'render_callback' => 'render_block_core_post_tags', - ) + register_block_type_from_metadata( + __DIR__ . '/post-tags', + array( + 'render_callback' => 'render_block_core_post_tags', ) ); } diff --git a/packages/block-library/src/post-title/block.json b/packages/block-library/src/post-title/block.json index b64dbc3740ab49..67502c3ba988d7 100644 --- a/packages/block-library/src/post-title/block.json +++ b/packages/block-library/src/post-title/block.json @@ -1,4 +1,5 @@ { "name": "core/post-title", - "category": "layout" + "category": "layout", + "context": [ "postId", "postType" ] } diff --git a/packages/block-library/src/post-title/edit.js b/packages/block-library/src/post-title/edit.js index ed9782fa4b5892..e06cdddee244a7 100644 --- a/packages/block-library/src/post-title/edit.js +++ b/packages/block-library/src/post-title/edit.js @@ -1,3 +1,24 @@ -export default function PostTitleEdit() { - return 'Post Title Placeholder'; +/** + * WordPress dependencies + */ +import { useSelect } from '@wordpress/data'; + +export default function PostTitleEdit( { context } ) { + const { postType, postId } = context; + + const post = useSelect( + ( select ) => + select( 'core' ).getEditedEntityRecord( + 'postType', + postType, + postId + ), + [ postType, postId ] + ); + + if ( ! post ) { + return null; + } + + return <h2>{ post.title }</h2>; } diff --git a/packages/block-library/src/post-title/index.php b/packages/block-library/src/post-title/index.php index c635ad2a0f0eb9..5d0ea451ea0c4f 100644 --- a/packages/block-library/src/post-title/index.php +++ b/packages/block-library/src/post-title/index.php @@ -8,30 +8,26 @@ /** * Renders the `core/post-title` block on the server. * + * @param WP_Block $block The block instance. + * * @return string Returns the filtered post title for the current post wrapped inside "h1" tags. */ -function render_block_core_post_title() { - $post = gutenberg_get_post_from_context(); - if ( ! $post ) { +function render_block_core_post_title( $block ) { + if ( ! isset( $block->context['postId'] ) ) { return ''; } - return '<h1>' . get_the_title( $post ) . '</h1>'; + + return '<h1>' . get_the_title( $block->context['postId'] ) . '</h1>'; } /** * Registers the `core/post-title` block on the server. */ function register_block_core_post_title() { - $path = __DIR__ . '/post-title/block.json'; - $metadata = json_decode( file_get_contents( $path ), true ); - - register_block_type( - $metadata['name'], - array_merge( - $metadata, - array( - 'render_callback' => 'render_block_core_post_title', - ) + register_block_type_from_metadata( + __DIR__ . '/post-title', + array( + 'render_callback' => 'render_block_core_post_title', ) ); } diff --git a/packages/block-library/src/preformatted/edit.js b/packages/block-library/src/preformatted/edit.js index 6a9bd052f0b59c..0acc7f26ae6c2a 100644 --- a/packages/block-library/src/preformatted/edit.js +++ b/packages/block-library/src/preformatted/edit.js @@ -2,7 +2,10 @@ * WordPress dependencies */ import { __ } from '@wordpress/i18n'; -import { RichText } from '@wordpress/block-editor'; +import { + RichText, + __experimentalBlock as Block, +} from '@wordpress/block-editor'; export default function PreformattedEdit( { attributes, @@ -15,7 +18,7 @@ export default function PreformattedEdit( { return ( <RichText - tagName="pre" + tagName={ Block.pre } identifier="content" preserveWhiteSpace value={ content } diff --git a/packages/block-library/src/preformatted/index.js b/packages/block-library/src/preformatted/index.js index cd18c639f7db1d..3fe52d58965739 100644 --- a/packages/block-library/src/preformatted/index.js +++ b/packages/block-library/src/preformatted/index.js @@ -24,13 +24,18 @@ export const settings = { icon, example: { attributes: { + /* eslint-disable @wordpress/i18n-no-collapsible-whitespace */ // translators: Sample content for the Preformatted block. Can be replaced with a more locale-adequate work. content: __( 'EXT. XANADU - FAINT DAWN - 1940 (MINIATURE)\nWindow, very small in the distance, illuminated.\nAll around this is an almost totally black screen. Now, as the camera moves slowly towards the window which is almost a postage stamp in the frame, other forms appear;' ), + /* eslint-enable @wordpress/i18n-no-collapsible-whitespace */ }, }, transforms, + supports: { + lightBlockWrapper: true, + }, edit, save, merge( attributes, attributesToMerge ) { diff --git a/packages/block-library/src/pullquote/blockquote.js b/packages/block-library/src/pullquote/blockquote.js new file mode 100644 index 00000000000000..287f2eef158466 --- /dev/null +++ b/packages/block-library/src/pullquote/blockquote.js @@ -0,0 +1 @@ +export const BlockQuote = 'blockquote'; diff --git a/packages/block-library/src/pullquote/blockquote.native.js b/packages/block-library/src/pullquote/blockquote.native.js new file mode 100644 index 00000000000000..36bfa0c582eef7 --- /dev/null +++ b/packages/block-library/src/pullquote/blockquote.native.js @@ -0,0 +1,29 @@ +/** + * External dependencies + */ +import { View } from 'react-native'; +/** + * WordPress dependencies + */ +import { Children, cloneElement } from '@wordpress/element'; +/** + * Internal dependencies + */ +import styles from './blockquote.scss'; + +export const BlockQuote = ( props ) => { + const newChildren = Children.map( props.children, ( child ) => { + if ( child && child.props.identifier === 'value' ) { + return cloneElement( child, { + style: styles.quote, + } ); + } + if ( child && child.props.identifier === 'citation' ) { + return cloneElement( child, { + style: styles.citation, + } ); + } + return child; + } ); + return <View>{ newChildren }</View>; +}; diff --git a/packages/block-library/src/pullquote/blockquote.native.scss b/packages/block-library/src/pullquote/blockquote.native.scss new file mode 100644 index 00000000000000..e8022091e99c68 --- /dev/null +++ b/packages/block-library/src/pullquote/blockquote.native.scss @@ -0,0 +1,8 @@ +.quote { + font-size: 18px; +} + +.citation { + font-size: 14px; + margin-top: 12px; +} diff --git a/packages/block-library/src/pullquote/edit.js b/packages/block-library/src/pullquote/edit.js index 5fead7277ec98b..5a7dae5a5f8451 100644 --- a/packages/block-library/src/pullquote/edit.js +++ b/packages/block-library/src/pullquote/edit.js @@ -16,6 +16,11 @@ import { withColors, PanelColorSettings, } from '@wordpress/block-editor'; +/** + * Internal dependencies + */ +import { Figure } from './figure'; +import { BlockQuote } from './blockquote'; /** * Internal dependencies @@ -124,12 +129,13 @@ class PullQuoteEdit extends Component { return ( <> - <figure style={ figureStyles } className={ figureClasses }> - <blockquote + <Figure style={ figureStyles } className={ figureClasses }> + <BlockQuote style={ blockquoteStyles } className={ blockquoteClasses } > <RichText + identifier="value" multiline value={ value } onChange={ ( nextValue ) => @@ -141,9 +147,11 @@ class PullQuoteEdit extends Component { // translators: placeholder text used for the quote __( 'Write quote…' ) } + textAlign="center" /> { ( ! RichText.isEmpty( citation ) || isSelected ) && ( <RichText + identifier="citation" value={ citation } placeholder={ // translators: placeholder text used for the citation @@ -155,10 +163,12 @@ class PullQuoteEdit extends Component { } ) } className="wp-block-pullquote__citation" + __unstableMobileNoFocusOnMount + textAlign="center" /> ) } - </blockquote> - </figure> + </BlockQuote> + </Figure> <InspectorControls> <PanelColorSettings title={ __( 'Color settings' ) } diff --git a/packages/block-library/src/pullquote/figure.js b/packages/block-library/src/pullquote/figure.js new file mode 100644 index 00000000000000..648af9ec6d5145 --- /dev/null +++ b/packages/block-library/src/pullquote/figure.js @@ -0,0 +1 @@ +export const Figure = 'figure'; diff --git a/packages/block-library/src/pullquote/figure.native.js b/packages/block-library/src/pullquote/figure.native.js new file mode 100644 index 00000000000000..57323c46ab6aec --- /dev/null +++ b/packages/block-library/src/pullquote/figure.native.js @@ -0,0 +1,23 @@ +/** + * External dependencies + */ +import { View } from 'react-native'; +/** + * WordPress dependencies + */ +import { withPreferredColorScheme } from '@wordpress/compose'; +/** + * Internal dependencies + */ +import styles from './figure.scss'; + +export const Figure = withPreferredColorScheme( ( props ) => { + const { children, getStylesFromColorScheme } = props; + + const wpPullquoteFigure = getStylesFromColorScheme( + styles.light, + styles.dark + ); + + return <View style={ wpPullquoteFigure }>{ children }</View>; +} ); diff --git a/packages/block-library/src/pullquote/figure.native.scss b/packages/block-library/src/pullquote/figure.native.scss new file mode 100644 index 00000000000000..e4f12c8c415fdc --- /dev/null +++ b/packages/block-library/src/pullquote/figure.native.scss @@ -0,0 +1,16 @@ +%shared { + border-width: 3px 0; + padding: 21px 16px; +} + +.light { + @extend %shared; + border-top-color: $gray-lighten-20; + border-bottom-color: $gray-lighten-20; +} + +.dark { + @extend %shared; + border-top-color: $gray-50; + border-bottom-color: $gray-50; +} diff --git a/packages/block-library/src/rss/block.json b/packages/block-library/src/rss/block.json new file mode 100644 index 00000000000000..8b4805cc062ca3 --- /dev/null +++ b/packages/block-library/src/rss/block.json @@ -0,0 +1,45 @@ +{ + "name": "core/rss", + "category": "widgets", + "attributes": { + "align": { + "type": "string", + "enum": [ "left", "center", "right", "wide", "full" ] + }, + "className": { + "type": "string" + }, + "columns": { + "type": "number", + "default": 2 + }, + "blockLayout": { + "type": "string", + "default": "list" + }, + "feedURL": { + "type": "string", + "default": "" + }, + "itemsToShow": { + "type": "number", + "default": 5 + }, + "displayExcerpt": { + "type": "boolean", + "default": false + }, + "displayAuthor": { + "type": "boolean", + "default": false + }, + "displayDate": { + "type": "boolean", + "default": false + }, + "excerptLength": { + "type": "number", + "default": 55 + } + } +} diff --git a/packages/block-library/src/rss/edit.js b/packages/block-library/src/rss/edit.js index 5c0a2ac6c74956..9e8ebe788d9743 100644 --- a/packages/block-library/src/rss/edit.js +++ b/packages/block-library/src/rss/edit.js @@ -1,7 +1,7 @@ /** * WordPress dependencies */ -import { Component } from '@wordpress/element'; +import { BlockControls, InspectorControls } from '@wordpress/block-editor'; import { Button, Disabled, @@ -12,169 +12,148 @@ import { ToggleControl, ToolbarGroup, } from '@wordpress/components'; +import { useState } from '@wordpress/element'; +import { grid, list, pencil, rss } from '@wordpress/icons'; import { __ } from '@wordpress/i18n'; -import { BlockControls, InspectorControls } from '@wordpress/block-editor'; import ServerSideRender from '@wordpress/server-side-render'; -import { rss, pencil, grid, list } from '@wordpress/icons'; const DEFAULT_MIN_ITEMS = 1; const DEFAULT_MAX_ITEMS = 10; -class RSSEdit extends Component { - constructor() { - super( ...arguments ); +export default function RSSEdit( { attributes, setAttributes } ) { + const [ isEditing, setIsEditing ] = useState( ! attributes.feedURL ); - this.state = { - editing: ! this.props.attributes.feedURL, - }; + const { + blockLayout, + columns, + displayAuthor, + displayDate, + displayExcerpt, + excerptLength, + feedURL, + itemsToShow, + } = attributes; - this.toggleAttribute = this.toggleAttribute.bind( this ); - this.onSubmitURL = this.onSubmitURL.bind( this ); - } - - toggleAttribute( propName ) { + function toggleAttribute( propName ) { return () => { - const value = this.props.attributes[ propName ]; - const { setAttributes } = this.props; + const value = attributes[ propName ]; setAttributes( { [ propName ]: ! value } ); }; } - onSubmitURL( event ) { + function onSubmitURL( event ) { event.preventDefault(); - const { feedURL } = this.props.attributes; if ( feedURL ) { - this.setState( { editing: false } ); + setIsEditing( false ); } } - render() { - const { - blockLayout, - columns, - displayAuthor, - displayExcerpt, - displayDate, - excerptLength, - feedURL, - itemsToShow, - } = this.props.attributes; - const { setAttributes } = this.props; + if ( isEditing ) { + return ( + <Placeholder icon={ rss } label="RSS"> + <form + onSubmit={ onSubmitURL } + className="wp-block-rss__placeholder-form" + > + <TextControl + placeholder={ __( 'Enter URL here…' ) } + value={ feedURL } + onChange={ ( value ) => + setAttributes( { feedURL: value } ) + } + className="wp-block-rss__placeholder-input" + /> + <Button isPrimary type="submit"> + { __( 'Use URL' ) } + </Button> + </form> + </Placeholder> + ); + } + + const toolbarControls = [ + { + icon: pencil, + title: __( 'Edit RSS URL' ), + onClick: () => setIsEditing( true ), + }, + { + icon: list, + title: __( 'List view' ), + onClick: () => setAttributes( { blockLayout: 'list' } ), + isActive: blockLayout === 'list', + }, + { + icon: grid, + title: __( 'Grid view' ), + onClick: () => setAttributes( { blockLayout: 'grid' } ), + isActive: blockLayout === 'grid', + }, + ]; - if ( this.state.editing ) { - return ( - <Placeholder icon={ rss } label="RSS"> - <form - onSubmit={ this.onSubmitURL } - className="blocks-rss__placeholder-form" - > - <TextControl - placeholder={ __( 'Enter URL here…' ) } - value={ feedURL } + return ( + <> + <BlockControls> + <ToolbarGroup controls={ toolbarControls } /> + </BlockControls> + <InspectorControls> + <PanelBody title={ __( 'RSS settings' ) }> + <RangeControl + label={ __( 'Number of items' ) } + value={ itemsToShow } + onChange={ ( value ) => + setAttributes( { itemsToShow: value } ) + } + min={ DEFAULT_MIN_ITEMS } + max={ DEFAULT_MAX_ITEMS } + required + /> + <ToggleControl + label={ __( 'Display author' ) } + checked={ displayAuthor } + onChange={ toggleAttribute( 'displayAuthor' ) } + /> + <ToggleControl + label={ __( 'Display date' ) } + checked={ displayDate } + onChange={ toggleAttribute( 'displayDate' ) } + /> + <ToggleControl + label={ __( 'Display excerpt' ) } + checked={ displayExcerpt } + onChange={ toggleAttribute( 'displayExcerpt' ) } + /> + { displayExcerpt && ( + <RangeControl + label={ __( 'Max number of words in excerpt' ) } + value={ excerptLength } onChange={ ( value ) => - setAttributes( { feedURL: value } ) + setAttributes( { excerptLength: value } ) } - className="blocks-rss__placeholder-input" + min={ 10 } + max={ 100 } + required /> - <Button isPrimary type="submit"> - { __( 'Use URL' ) } - </Button> - </form> - </Placeholder> - ); - } - - const toolbarControls = [ - { - icon: pencil, - title: __( 'Edit RSS URL' ), - onClick: () => this.setState( { editing: true } ), - }, - { - icon: list, - title: __( 'List view' ), - onClick: () => setAttributes( { blockLayout: 'list' } ), - isActive: blockLayout === 'list', - }, - { - icon: grid, - title: __( 'Grid view' ), - onClick: () => setAttributes( { blockLayout: 'grid' } ), - isActive: blockLayout === 'grid', - }, - ]; - - return ( - <> - <BlockControls> - <ToolbarGroup controls={ toolbarControls } /> - </BlockControls> - <InspectorControls> - <PanelBody title={ __( 'RSS settings' ) }> + ) } + { blockLayout === 'grid' && ( <RangeControl - label={ __( 'Number of items' ) } - value={ itemsToShow } + label={ __( 'Columns' ) } + value={ columns } onChange={ ( value ) => - setAttributes( { itemsToShow: value } ) + setAttributes( { columns: value } ) } - min={ DEFAULT_MIN_ITEMS } - max={ DEFAULT_MAX_ITEMS } + min={ 2 } + max={ 6 } required /> - <ToggleControl - label={ __( 'Display author' ) } - checked={ displayAuthor } - onChange={ this.toggleAttribute( 'displayAuthor' ) } - /> - <ToggleControl - label={ __( 'Display date' ) } - checked={ displayDate } - onChange={ this.toggleAttribute( 'displayDate' ) } - /> - <ToggleControl - label={ __( 'Display excerpt' ) } - checked={ displayExcerpt } - onChange={ this.toggleAttribute( - 'displayExcerpt' - ) } - /> - { displayExcerpt && ( - <RangeControl - label={ __( 'Max number of words in excerpt' ) } - value={ excerptLength } - onChange={ ( value ) => - setAttributes( { excerptLength: value } ) - } - min={ 10 } - max={ 100 } - required - /> - ) } - { blockLayout === 'grid' && ( - <RangeControl - label={ __( 'Columns' ) } - value={ columns } - onChange={ ( value ) => - setAttributes( { columns: value } ) - } - min={ 2 } - max={ 6 } - required - /> - ) } - </PanelBody> - </InspectorControls> - <Disabled> - <ServerSideRender - block="core/rss" - attributes={ this.props.attributes } - /> - </Disabled> - </> - ); - } + ) } + </PanelBody> + </InspectorControls> + <Disabled> + <ServerSideRender block="core/rss" attributes={ attributes } /> + </Disabled> + </> + ); } - -export default RSSEdit; diff --git a/packages/block-library/src/rss/editor.scss b/packages/block-library/src/rss/editor.scss index cff2b35ae36db6..7b08c85d3b55f8 100644 --- a/packages/block-library/src/rss/editor.scss +++ b/packages/block-library/src/rss/editor.scss @@ -8,7 +8,7 @@ display: inline; } -.blocks-rss__placeholder-form { +.wp-block-rss__placeholder-form { display: flex; align-items: stretch; @@ -23,7 +23,7 @@ } } -.blocks-rss__placeholder-input { +.wp-block-rss__placeholder-input { display: flex; align-items: stretch; flex-grow: 1; diff --git a/packages/block-library/src/rss/index.js b/packages/block-library/src/rss/index.js index 461bc6c59bff63..fc0144be2efb36 100644 --- a/packages/block-library/src/rss/index.js +++ b/packages/block-library/src/rss/index.js @@ -1,21 +1,23 @@ /** * WordPress dependencies */ -import { __ } from '@wordpress/i18n'; import { rss as icon } from '@wordpress/icons'; +import { __ } from '@wordpress/i18n'; /** * Internal dependencies */ +import metadata from './block.json'; import edit from './edit'; -export const name = 'core/rss'; +const { name } = metadata; + +export { metadata, name }; export const settings = { title: __( 'RSS' ), description: __( 'Display entries from any RSS or Atom feed.' ), icon, - category: 'widgets', keywords: [ __( 'atom' ), __( 'feed' ) ], supports: { align: true, diff --git a/packages/block-library/src/rss/index.php b/packages/block-library/src/rss/index.php index 07ddb3d007e53e..f98f6343c121b2 100644 --- a/packages/block-library/src/rss/index.php +++ b/packages/block-library/src/rss/index.php @@ -92,57 +92,16 @@ function render_block_core_rss( $attributes ) { $class .= ' ' . $attributes['className']; } - return sprintf( "<ul class='%s'>%s</ul>", esc_attr( $class ), $list_items ); + return sprintf( '<ul class="%s">%s</ul>', esc_attr( $class ), $list_items ); } /** * Registers the `core/rss` block on server. */ function register_block_core_rss() { - register_block_type( - 'core/rss', + register_block_type_from_metadata( + __DIR__ . '/rss', array( - 'attributes' => array( - 'align' => array( - 'type' => 'string', - 'enum' => array( 'left', 'center', 'right', 'wide', 'full' ), - ), - 'className' => array( - 'type' => 'string', - ), - 'columns' => array( - 'type' => 'number', - 'default' => 2, - ), - 'blockLayout' => array( - 'type' => 'string', - 'default' => 'list', - ), - 'feedURL' => array( - 'type' => 'string', - 'default' => '', - ), - 'itemsToShow' => array( - 'type' => 'number', - 'default' => 5, - ), - 'displayExcerpt' => array( - 'type' => 'boolean', - 'default' => false, - ), - 'displayAuthor' => array( - 'type' => 'boolean', - 'default' => false, - ), - 'displayDate' => array( - 'type' => 'boolean', - 'default' => false, - ), - 'excerptLength' => array( - 'type' => 'number', - 'default' => 55, - ), - ), 'render_callback' => 'render_block_core_rss', ) ); diff --git a/packages/block-library/src/separator/style.scss b/packages/block-library/src/separator/style.scss index a4cf1f2fdb6d27..8decc9d0ba52dd 100644 --- a/packages/block-library/src/separator/style.scss +++ b/packages/block-library/src/separator/style.scss @@ -22,6 +22,7 @@ color: currentColor; font-size: 20px; letter-spacing: 2em; + /*rtl:ignore*/ padding-left: 2em; font-family: serif; } diff --git a/packages/block-library/src/shortcode/index.php b/packages/block-library/src/shortcode/index.php index cfa8ab97dfa2bc..97a40b386d9c92 100644 --- a/packages/block-library/src/shortcode/index.php +++ b/packages/block-library/src/shortcode/index.php @@ -21,15 +21,10 @@ function render_block_core_shortcode( $attributes, $content ) { * Registers the `core/shortcode` block on server. */ function register_block_core_shortcode() { - $path = __DIR__ . '/shortcode/block.json'; - $metadata = json_decode( file_get_contents( $path ), true ); - register_block_type( - $metadata['name'], - array_merge( - $metadata, - array( - 'render_callback' => 'render_block_core_shortcode', - ) + register_block_type_from_metadata( + __DIR__ . '/shortcode', + array( + 'render_callback' => 'render_block_core_shortcode', ) ); } diff --git a/packages/block-library/src/site-title/edit.js b/packages/block-library/src/site-title/edit.js index 382493e17c8c5d..55661ca1ae9b29 100644 --- a/packages/block-library/src/site-title/edit.js +++ b/packages/block-library/src/site-title/edit.js @@ -3,12 +3,13 @@ */ import { useEntityProp } from '@wordpress/core-data'; import { __ } from '@wordpress/i18n'; -import { Editable } from '@wordpress/block-editor'; +import { PlainText } from '@wordpress/block-editor'; export default function SiteTitleEdit() { const [ title, setTitle ] = useEntityProp( 'root', 'site', 'title' ); return ( - <Editable + <PlainText + __experimentalVersion={ 2 } tagName="h1" placeholder={ __( 'Site Title' ) } value={ title } diff --git a/packages/block-library/src/site-title/index.php b/packages/block-library/src/site-title/index.php index a63760983436e2..7241bc50dffa56 100644 --- a/packages/block-library/src/site-title/index.php +++ b/packages/block-library/src/site-title/index.php @@ -24,16 +24,10 @@ function render_block_core_site_title( $attributes ) { * Registers the `core/site-title` block on the server. */ function register_block_core_site_title() { - $path = __DIR__ . '/site-title/block.json'; - $metadata = json_decode( file_get_contents( $path ), true ); - - register_block_type( - $metadata['name'], - array_merge( - $metadata, - array( - 'render_callback' => 'render_block_core_site_title', - ) + register_block_type_from_metadata( + __DIR__ . '/site-title', + array( + 'render_callback' => 'render_block_core_site_title', ) ); } diff --git a/packages/block-library/src/social-link/block.json b/packages/block-library/src/social-link/block.json index 977f5731fd961a..a9725b56781f58 100644 --- a/packages/block-library/src/social-link/block.json +++ b/packages/block-library/src/social-link/block.json @@ -1,7 +1,6 @@ { "name": "core/social-link", "category": "widgets", - "icon": "share", "attributes": { "url": { "type": "string" diff --git a/packages/block-library/src/social-link/edit.js b/packages/block-library/src/social-link/edit.js index 2dd4e747638c28..3a02741fce0b15 100644 --- a/packages/block-library/src/social-link/edit.js +++ b/packages/block-library/src/social-link/edit.js @@ -33,7 +33,6 @@ const SocialLinkEdit = ( { attributes, setAttributes, isSelected } ) => { 'wp-social-link__is-incomplete': ! url, } ); - // Import icon. const IconComponent = getIconBySite( service ); const socialLinkName = getNameBySite( service ); @@ -41,7 +40,11 @@ const SocialLinkEdit = ( { attributes, setAttributes, isSelected } ) => { <Fragment> <InspectorControls> <PanelBody - title={ sprintf( __( '%s label' ), socialLinkName ) } + title={ sprintf( + /* translators: %s: name of the social service. */ + __( '%s label' ), + socialLinkName + ) } initialOpen={ false } > <PanelRow> diff --git a/packages/block-library/src/social-link/icons/tumblr.js b/packages/block-library/src/social-link/icons/tumblr.js index 5999fe4ead681d..e696d2955fb444 100644 --- a/packages/block-library/src/social-link/icons/tumblr.js +++ b/packages/block-library/src/social-link/icons/tumblr.js @@ -5,6 +5,6 @@ import { Path, SVG } from '@wordpress/primitives'; export const TumblrIcon = () => ( <SVG width="24" height="24" viewBox="0 0 24 24" version="1.1"> - <Path d="M16.749,17.396c-0.357,0.17-1.041,0.319-1.551,0.332c-1.539,0.041-1.837-1.081-1.85-1.896V9.847h3.861V6.937h-3.847V2.039 c0,0-2.77,0-2.817,0c-0.046,0-0.127,0.041-0.138,0.144c-0.165,1.499-0.867,4.13-3.783,5.181v2.484h1.945v6.282 c0,2.151,1.587,5.206,5.775,5.135c1.413-0.024,2.982-0.616,3.329-1.126L16.749,17.396z" /> + <Path d="M17.04 21.28h-3.28c-2.84 0-4.94-1.37-4.94-5.02v-5.67H6.08V7.5c2.93-.73 4.11-3.3 4.3-5.48h3.01v4.93h3.47v3.65H13.4v4.93c0 1.47.73 2.01 1.92 2.01h1.73v3.75z" /> </SVG> ); diff --git a/packages/block-library/src/social-link/index.js b/packages/block-library/src/social-link/index.js index bebeaad5832af4..771f364541f3e1 100644 --- a/packages/block-library/src/social-link/index.js +++ b/packages/block-library/src/social-link/index.js @@ -2,6 +2,7 @@ * WordPress dependencies */ import { __ } from '@wordpress/i18n'; +import { share as icon } from '@wordpress/icons'; /** * Internal dependencies @@ -21,6 +22,7 @@ export const settings = { reusable: false, html: false, }, + icon, edit, description: __( 'Display an icon linking to a social media profile or website.' diff --git a/packages/block-library/src/social-link/index.php b/packages/block-library/src/social-link/index.php index 32111ff72db732..dc732a7a1f90ed 100644 --- a/packages/block-library/src/social-link/index.php +++ b/packages/block-library/src/social-link/index.php @@ -13,12 +13,10 @@ * @return string Rendered HTML of the referenced block. */ function render_block_core_social_link( $attributes ) { - $service = ( isset( $attributes['service'] ) ) ? $attributes['service'] : 'Icon'; - $url = ( isset( $attributes['url'] ) ) ? $attributes['url'] : false; - $label = ( isset( $attributes['label'] ) ) ? - $attributes['label'] : - /* translators: %s: Social Link service name */ - sprintf( __( 'Link to %s' ), block_core_social_link_get_name( $service ) ); + $service = ( isset( $attributes['service'] ) ) ? $attributes['service'] : 'Icon'; + $url = ( isset( $attributes['url'] ) ) ? $attributes['url'] : false; + $label = ( isset( $attributes['label'] ) ) ? $attributes['label'] : block_core_social_link_get_name( $service ); + $class_name = isset( $attributes['className'] ) ? ' ' . $attributes['className'] : false; // Don't render a link if there is no URL set. if ( ! $url ) { @@ -26,23 +24,17 @@ function render_block_core_social_link( $attributes ) { } $icon = block_core_social_link_get_icon( $service ); - return '<li class="wp-social-link wp-social-link-' . esc_attr( $service ) . '"><a href="' . esc_url( $url ) . '" aria-label="' . esc_attr( $label ) . '"> ' . $icon . '</a></li>'; + return '<li class="wp-social-link wp-social-link-' . esc_attr( $service ) . esc_attr( $class_name ) . '"><a href="' . esc_url( $url ) . '" aria-label="' . esc_attr( $label ) . '"> ' . $icon . '</a></li>'; } /** * Registers the `core/social-link` blocks. */ function register_block_core_social_link() { - $path = __DIR__ . '/social-link/block.json'; - $metadata = json_decode( file_get_contents( $path ), true ); - - register_block_type( - $metadata['name'], - array_merge( - $metadata, - array( - 'render_callback' => 'render_block_core_social_link', - ) + register_block_type_from_metadata( + __DIR__ . '/social-link', + array( + 'render_callback' => 'render_block_core_social_link', ) ); } @@ -217,7 +209,7 @@ function block_core_social_link_services( $service = '', $field = '' ) { ), 'tumblr' => array( 'name' => 'Tumblr', - 'icon' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" role="img" aria-hidden="true" focusable="false"><path d="M16.749,17.396c-0.357,0.17-1.041,0.319-1.551,0.332c-1.539,0.041-1.837-1.081-1.85-1.896V9.847h3.861V6.937h-3.847V2.039 c0,0-2.77,0-2.817,0c-0.046,0-0.127,0.041-0.138,0.144c-0.165,1.499-0.867,4.13-3.783,5.181v2.484h1.945v6.282 c0,2.151,1.587,5.206,5.775,5.135c1.413-0.024,2.982-0.616,3.329-1.126L16.749,17.396z"></path></svg>', + 'icon' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" role="img" aria-hidden="true" focusable="false"><path d="M17.04 21.28h-3.28c-2.84 0-4.94-1.37-4.94-5.02v-5.67H6.08V7.5c2.93-.73 4.11-3.3 4.3-5.48h3.01v4.93h3.47v3.65H13.4v4.93c0 1.47.73 2.01 1.92 2.01h1.73v3.75z" /></path></svg>', ), 'twitch' => array( 'name' => 'Twitch', @@ -249,7 +241,7 @@ function block_core_social_link_services( $service = '', $field = '' ) { ), 'share' => array( 'name' => 'Share Icon', - 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" role="img" aria-hidden="true" focusable="false"><rect x="0" fill="none" width="20" height="20"/><g><path d="M14.5 12c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3c0-.24.03-.46.09-.69l-4.38-2.3c-.55.61-1.33.99-2.21.99-1.66 0-3-1.34-3-3s1.34-3 3-3c.88 0 1.66.39 2.21.99l4.38-2.3c-.06-.23-.09-.45-.09-.69 0-1.66 1.34-3 3-3s3 1.34 3 3-1.34 3-3 3c-.88 0-1.66-.39-2.21-.99l-4.38 2.3c.06.23.09.45.09.69s-.03.46-.09.69l4.38 2.3c.55-.61 1.33-.99 2.21-.99z"/></g></svg>', + 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9 11.8l6.1-4.5c.1.4.4.7.9.7h2c.6 0 1-.4 1-1V5c0-.6-.4-1-1-1h-2c-.6 0-1 .4-1 1v.4l-6.4 4.8c-.2-.1-.4-.2-.6-.2H6c-.6 0-1 .4-1 1v2c0 .6.4 1 1 1h2c.2 0 .4-.1.6-.2l6.4 4.8v.4c0 .6.4 1 1 1h2c.6 0 1-.4 1-1v-2c0-.6-.4-1-1-1h-2c-.5 0-.8.3-.9.7L9 12.2v-.4z"/></svg>', ), ); diff --git a/packages/block-library/src/social-links/block.json b/packages/block-library/src/social-links/block.json index 6d25baacb1a857..3019a7f5c3b397 100644 --- a/packages/block-library/src/social-links/block.json +++ b/packages/block-library/src/social-links/block.json @@ -1,6 +1,5 @@ { "name": "core/social-links", "category": "widgets", - "icon": "share", "attributes": {} } diff --git a/packages/block-library/src/social-links/index.js b/packages/block-library/src/social-links/index.js index 3eb0027959a09d..2c27f8daad2b65 100644 --- a/packages/block-library/src/social-links/index.js +++ b/packages/block-library/src/social-links/index.js @@ -2,6 +2,7 @@ * WordPress dependencies */ import { __, _x } from '@wordpress/i18n'; +import { share as icon } from '@wordpress/icons'; /** * Internal dependencies @@ -53,6 +54,7 @@ export const settings = { { name: 'logos-only', label: __( 'Logos Only' ) }, { name: 'pill-shape', label: __( 'Pill Shape' ) }, ], + icon, edit, save, }; diff --git a/packages/block-library/src/social-links/style.scss b/packages/block-library/src/social-links/style.scss index 3bfa4992e224a8..9a6f2adabea130 100644 --- a/packages/block-library/src/social-links/style.scss +++ b/packages/block-library/src/social-links/style.scss @@ -102,7 +102,7 @@ } .wp-social-link-facebook { - background-color: #1977f2; + background-color: #1778f2; color: #fff; } @@ -147,7 +147,7 @@ } .wp-social-link-linkedin { - background-color: #0577b5; + background-color: #0d66c2; color: #fff; } @@ -213,7 +213,7 @@ } .wp-social-link-twitter { - background-color: #21a1f3; + background-color: #1da1f2; color: #fff; } @@ -238,7 +238,7 @@ } .wp-social-link-youtube { - background-color: #ff0100; + background-color: #f00; color: #fff; } } @@ -289,7 +289,7 @@ } .wp-social-link-facebook { - color: #1977f2; + color: #1778f2; } .wp-social-link-fivehundredpx { @@ -325,7 +325,7 @@ } .wp-social-link-linkedin { - color: #0577b5; + color: #0d66c2; } .wp-social-link-mastodon { @@ -378,7 +378,7 @@ } .wp-social-link-twitter { - color: #21a1f3; + color: #1da1f2; } .wp-social-link-vimeo { @@ -399,7 +399,7 @@ } .wp-social-link-youtube { - color: #ff0100; + color: #f00; } } diff --git a/packages/block-library/src/spacer/edit.js b/packages/block-library/src/spacer/edit.js index 76993d3977207c..9a457c6e8ad173 100644 --- a/packages/block-library/src/spacer/edit.js +++ b/packages/block-library/src/spacer/edit.js @@ -11,6 +11,7 @@ import { InspectorControls } from '@wordpress/block-editor'; import { PanelBody, ResizableBox, RangeControl } from '@wordpress/components'; import { compose, withInstanceId } from '@wordpress/compose'; import { withDispatch } from '@wordpress/data'; +import { Platform } from '@wordpress/element'; const MIN_SPACER_HEIGHT = 20; const MAX_SPACER_HEIGHT = 500; @@ -72,7 +73,7 @@ const SpacerEdit = ( { separatorType={ 'none' } value={ height } onChange={ updateHeight } - step={ 10 } + step={ Platform.OS === 'web' ? 10 : 1 } /> </PanelBody> </InspectorControls> diff --git a/packages/block-library/src/style.scss b/packages/block-library/src/style.scss index bd8ab8a093bb5c..19b1d3208d4e52 100644 --- a/packages/block-library/src/style.scss +++ b/packages/block-library/src/style.scss @@ -13,6 +13,7 @@ @import "./embed/style.scss"; @import "./file/style.scss"; @import "./gallery/style.scss"; +@import "./heading/style.scss"; @import "./image/style.scss"; @import "./latest-comments/style.scss"; @import "./latest-posts/style.scss"; @@ -215,28 +216,30 @@ // Font sizes. +:root { + .has-small-font-size { + font-size: 13px; + } -.has-small-font-size { - font-size: 13px; -} + .has-regular-font-size, // Not used now, kept because of backward compatibility. + .has-normal-font-size { + font-size: 16px; + } -.has-regular-font-size, // Not used now, kept because of backward compatibility. -.has-normal-font-size { - font-size: 16px; -} + .has-medium-font-size { + font-size: 20px; + } -.has-medium-font-size { - font-size: 20px; -} + .has-large-font-size { + font-size: 36px; + } -.has-large-font-size { - font-size: 36px; + .has-larger-font-size, // Not used now, kept because of backward compatibility. + .has-huge-font-size { + font-size: 42px; + } } -.has-larger-font-size, // Not used now, kept because of backward compatibility. -.has-huge-font-size { - font-size: 42px; -} // Text alignments. .has-text-align-center { @@ -257,3 +260,8 @@ #end-resizable-editor-section { display: none; } + +// Block alignments. +.aligncenter { + clear: both; +} diff --git a/packages/block-library/src/tag-cloud/index.js b/packages/block-library/src/tag-cloud/index.js index 62291e0ad81d45..e8090c70afca12 100644 --- a/packages/block-library/src/tag-cloud/index.js +++ b/packages/block-library/src/tag-cloud/index.js @@ -20,5 +20,6 @@ export const settings = { html: false, align: true, }, + example: {}, edit, }; diff --git a/packages/block-library/src/template-part/edit/placeholder.js b/packages/block-library/src/template-part/edit/placeholder.js index abeb2d12139ef8..f3b3f7bc43e48d 100644 --- a/packages/block-library/src/template-part/edit/placeholder.js +++ b/packages/block-library/src/template-part/edit/placeholder.js @@ -22,14 +22,14 @@ function TemplatePartPreview() { <div className="wp-block-template-part__placeholder-preview-title"> { __( 'Preview' ) } </div> - <BlockPreview blocks={ blocks } /> + <BlockPreview blocks={ blocks } viewportWidth={ 1200 } /> </div> ); } export default function TemplatePartPlaceholder( { setAttributes } ) { - const [ slug, _setSlug ] = useState(); - const [ theme, setTheme ] = useState(); + const [ slug, _setSlug ] = useState( '' ); + const [ theme, setTheme ] = useState( '' ); const [ help, setHelp ] = useState(); // Try to find an existing template part. diff --git a/packages/block-library/src/template-part/index.js b/packages/block-library/src/template-part/index.js index 86b2c4cd2742e4..135b7a560e6b30 100644 --- a/packages/block-library/src/template-part/index.js +++ b/packages/block-library/src/template-part/index.js @@ -1,3 +1,8 @@ +/** + * External dependencies + */ +import { startCase } from 'lodash'; + /** * WordPress dependencies */ @@ -17,5 +22,6 @@ export const settings = { supports: { html: false, }, + __experimentalLabel: ( { slug } ) => startCase( slug ), edit, }; diff --git a/packages/block-library/src/template-part/index.php b/packages/block-library/src/template-part/index.php index 1a2c4403ba10f4..e5a785e983ef37 100644 --- a/packages/block-library/src/template-part/index.php +++ b/packages/block-library/src/template-part/index.php @@ -22,9 +22,8 @@ function render_block_core_template_part( $attributes ) { } elseif ( wp_get_theme()->get( 'TextDomain' ) === $attributes['theme'] ) { // Else, if the template part was provided by the active theme, // render the corresponding file content. - $template_part_file_path = - get_stylesheet_directory() . '/block-template-parts/' . $attributes['slug'] . '.html'; - if ( file_exists( $template_part_file_path ) ) { + $template_part_file_path = get_stylesheet_directory() . '/block-template-parts/' . $attributes['slug'] . '.html'; + if ( 0 === validate_file( $template_part_file_path ) && file_exists( $template_part_file_path ) ) { $content = file_get_contents( $template_part_file_path ); } } @@ -39,7 +38,11 @@ function render_block_core_template_part( $attributes ) { $content = convert_smilies( $content ); $content = wpautop( $content ); $content = shortcode_unautop( $content ); - $content = wp_make_content_images_responsive( $content ); + if ( function_exists( 'wp_filter_content_tags' ) ) { + $content = wp_filter_content_tags( $content ); + } else { + $content = wp_make_content_images_responsive( $content ); + } $content = do_shortcode( $content ); return str_replace( ']]>', ']]&gt;', $content ); diff --git a/packages/block-library/src/verse/edit.js b/packages/block-library/src/verse/edit.js index 82a184ce167904..2c33afb53fd818 100644 --- a/packages/block-library/src/verse/edit.js +++ b/packages/block-library/src/verse/edit.js @@ -11,6 +11,7 @@ import { RichText, BlockControls, AlignmentToolbar, + __experimentalBlock as Block, } from '@wordpress/block-editor'; export default function VerseEdit( { @@ -32,7 +33,7 @@ export default function VerseEdit( { /> </BlockControls> <RichText - tagName="pre" + tagName={ Block.pre } preserveWhiteSpace value={ content } onChange={ ( nextContent ) => { diff --git a/packages/block-library/src/verse/index.js b/packages/block-library/src/verse/index.js index e05ab62bf2f27f..04f41e2f6de0cf 100644 --- a/packages/block-library/src/verse/index.js +++ b/packages/block-library/src/verse/index.js @@ -25,12 +25,17 @@ export const settings = { icon, example: { attributes: { + /* eslint-disable @wordpress/i18n-no-collapsible-whitespace */ // translators: Sample content for the Verse block. Can be replaced with a more locale-adequate work. content: __( 'WHAT was he doing, the great god Pan,\n Down in the reeds by the river?\nSpreading ruin and scattering ban,\nSplashing and paddling with hoofs of a goat,\nAnd breaking the golden lilies afloat\n With the dragon-fly on the river.' ), + /* eslint-enable @wordpress/i18n-no-collapsible-whitespace */ }, }, + supports: { + lightBlockWrapper: true, + }, keywords: [ __( 'poetry' ), __( 'poem' ) ], transforms, deprecated, diff --git a/packages/block-library/src/video/edit.js b/packages/block-library/src/video/edit.js index fc359c655cb986..52a5db7c44fb12 100644 --- a/packages/block-library/src/video/edit.js +++ b/packages/block-library/src/video/edit.js @@ -200,6 +200,7 @@ class VideoEdit extends Component { <p id={ videoPosterDescription } hidden> { this.props.attributes.poster ? sprintf( + /* translators: %s: poster image URL. */ __( 'The current poster image url is %s' ), diff --git a/packages/block-serialization-default-parser/package.json b/packages/block-serialization-default-parser/package.json index fdefc9a59fa7bd..21a63e95685b5a 100644 --- a/packages/block-serialization-default-parser/package.json +++ b/packages/block-serialization-default-parser/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-serialization-default-parser", - "version": "3.5.0", + "version": "3.6.0", "description": "Block serialization specification parser for WordPress posts.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -23,7 +23,7 @@ "react-native": "src/index", "sideEffects": false, "dependencies": { - "@babel/runtime": "^7.8.3" + "@babel/runtime": "^7.9.2" }, "publishConfig": { "access": "public" diff --git a/packages/block-serialization-default-parser/src/index.js b/packages/block-serialization-default-parser/src/index.js index cc6f61e5fe7352..c6a844d0cc6dd7 100644 --- a/packages/block-serialization-default-parser/src/index.js +++ b/packages/block-serialization-default-parser/src/index.js @@ -39,7 +39,7 @@ let stack; * once browsers reliably support atomic grouping or possessive * quantifiers natively we should remove this trick and simplify * - * @type RegExp + * @type {RegExp} * * @since 3.8.0 * @since 4.6.1 added optimization to prevent backtracking on attribute parsing diff --git a/packages/block-serialization-spec-parser/.eslintrc.json b/packages/block-serialization-spec-parser/.eslintrc.json index ffee0154641f1d..363e55181855b4 100644 --- a/packages/block-serialization-spec-parser/.eslintrc.json +++ b/packages/block-serialization-spec-parser/.eslintrc.json @@ -4,7 +4,10 @@ "files": [ "shared-tests.js" ], "extends": [ "plugin:@wordpress/eslint-plugin/test-unit" - ] + ], + "rules": { + "jest/no-export": "off" + } } ] } diff --git a/packages/block-serialization-spec-parser/package.json b/packages/block-serialization-spec-parser/package.json index 1c5e9f2c6d715a..580e2a3d4713a2 100644 --- a/packages/block-serialization-spec-parser/package.json +++ b/packages/block-serialization-spec-parser/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-serialization-spec-parser", - "version": "3.4.0", + "version": "3.5.0", "description": "Block serialization specification parser for WordPress posts.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/blocks/CHANGELOG.md b/packages/blocks/CHANGELOG.md index 9ec34c5fac6a2f..9e6d1bbcf40fc7 100644 --- a/packages/blocks/CHANGELOG.md +++ b/packages/blocks/CHANGELOG.md @@ -1,5 +1,7 @@ ## Master +## 6.13.0 (2020-04-01) + ### New Feature - Blocks can now be registered with an `defaultStylePicker` flag in the `supports` setting, allowing the default style picker to be removed. diff --git a/packages/blocks/package.json b/packages/blocks/package.json index d8c30fe656a5fe..2fc125781fde76 100644 --- a/packages/blocks/package.json +++ b/packages/blocks/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/blocks", - "version": "6.12.1", + "version": "6.14.1", "description": "Block API for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -21,7 +21,7 @@ "module": "build-module/index.js", "react-native": "src/index", "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/autop": "file:../autop", "@wordpress/blob": "file:../blob", "@wordpress/block-serialization-default-parser": "file:../block-serialization-default-parser", @@ -41,7 +41,7 @@ "showdown": "^1.8.6", "simple-html-tokenizer": "^0.5.7", "tinycolor2": "^1.4.1", - "uuid": "^3.3.2" + "uuid": "^7.0.2" }, "publishConfig": { "access": "public" diff --git a/packages/blocks/src/api/factory.js b/packages/blocks/src/api/factory.js index 983bafd73caabe..8775b6f78ea013 100644 --- a/packages/blocks/src/api/factory.js +++ b/packages/blocks/src/api/factory.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import uuid from 'uuid/v4'; +import { v4 as uuid } from 'uuid'; import { every, reduce, diff --git a/packages/blocks/src/api/raw-handling/html-formatting-remover.js b/packages/blocks/src/api/raw-handling/html-formatting-remover.js index b44fbe71deff1f..b5a9f6b75420b6 100644 --- a/packages/blocks/src/api/raw-handling/html-formatting-remover.js +++ b/packages/blocks/src/api/raw-handling/html-formatting-remover.js @@ -25,9 +25,21 @@ export default function( node ) { return; } - // Ignore pre content. - if ( node.parentElement.closest( 'pre' ) ) { - return; + // Ignore pre content. Note that this does not use Element#closest due to + // a combination of (a) node may not be Element and (b) node.parentElement + // does not have full support in all browsers (Internet Exporer). + // + // See: https://developer.mozilla.org/en-US/docs/Web/API/Node/parentElement#Browser_compatibility + + /** @type {Node?} */ + let parent = node; + while ( ( parent = parent.parentNode ) ) { + if ( + parent.nodeType === window.Node.ELEMENT_NODE && + parent.nodeName === 'PRE' + ) { + return; + } } // First, replace any sequence of HTML formatting space with a single space. diff --git a/packages/blocks/src/api/raw-handling/test/html-formatting-remover.js b/packages/blocks/src/api/raw-handling/test/html-formatting-remover.js index d5efd50f4db857..64df51a4f781b6 100644 --- a/packages/blocks/src/api/raw-handling/test/html-formatting-remover.js +++ b/packages/blocks/src/api/raw-handling/test/html-formatting-remover.js @@ -2,7 +2,7 @@ * Internal dependencies */ import filter from '../html-formatting-remover'; -import { deepFilterHTML } from '../utils'; +import { deepFilterHTML, deepFilterNodeList } from '../utils'; describe( 'HTMLFormattingRemover', () => { it( 'should trim text node without parent', () => { @@ -102,6 +102,24 @@ describe( 'HTMLFormattingRemover', () => { expect( deepFilterHTML( input, [ filter ] ) ).toEqual( input ); } ); + it( 'should tolerate browser quirks of DOM parent property availability', () => { + const input = 'a'; + + const doc = document.implementation.createHTMLDocument( '' ); + doc.body.innerHTML = input; + + // Emulate absence of `parentElement` property. + // See: https://developer.mozilla.org/en-US/docs/Web/API/Node/parentElement#Browser_compatibility + Object.defineProperty( doc.body.firstChild, 'parentElement', { + get() { + return undefined; + }, + } ); + + deepFilterNodeList( doc.body.childNodes, [ filter ], doc ); + expect( doc.body.innerHTML ).toEqual( input ); + } ); + it( 'should not remove white space if next elemnt has none', () => { const input = `<div><strong>a </strong>b</div>`; const output = '<div><strong>a </strong>b</div>'; diff --git a/packages/blocks/src/api/utils.js b/packages/blocks/src/api/utils.js index 11b333d8bdef23..dbf1dc79049b9d 100644 --- a/packages/blocks/src/api/utils.js +++ b/packages/blocks/src/api/utils.js @@ -184,7 +184,7 @@ export function getAccessibleBlockLabel( if ( hasPosition && direction === 'vertical' ) { if ( hasLabel ) { return sprintf( - /* translators: accessibility text. %1: The block title, %2: The block row number, %3: The block label.. */ + /* translators: accessibility text. 1: The block title. 2: The block row number. 3: The block label.. */ __( '%1$s Block. Row %2$d. %3$s' ), title, position, @@ -193,15 +193,15 @@ export function getAccessibleBlockLabel( } return sprintf( - /* translators: accessibility text. %s: The block title, %d The block row number. */ - __( '%s Block. Row %d' ), + /* translators: accessibility text. 1: The block title. 2: The block row number. */ + __( '%1$s Block. Row %2$d' ), title, position ); } else if ( hasPosition && direction === 'horizontal' ) { if ( hasLabel ) { return sprintf( - /* translators: accessibility text. %1: The block title, %2: The block column number, %3: The block label.. */ + /* translators: accessibility text. 1: The block title. 2: The block column number. 3: The block label.. */ __( '%1$s Block. Column %2$d. %3$s' ), title, position, @@ -210,8 +210,8 @@ export function getAccessibleBlockLabel( } return sprintf( - /* translators: accessibility text. %s: The block title, %d The block column number. */ - __( '%s Block. Column %d' ), + /* translators: accessibility text. 1: The block title. 2: The block column number. */ + __( '%1$s Block. Column %2$d' ), title, position ); diff --git a/packages/components/README.md b/packages/components/README.md index fb82b7f526f860..a035497b5d59db 100644 --- a/packages/components/README.md +++ b/packages/components/README.md @@ -27,6 +27,8 @@ export default function MyButton() { } ``` -Many components also include styles which will need to be output in order to appear correctly. Within WordPress, you can [add the `wp-components` stylesheet as a dependency of your plugin's stylesheet](https://developer.wordpress.org/reference/functions/wp_enqueue_style/#parameters). In other projects, you can link to the `build-style/style.css` file directly. +Many components include CSS to add style, you will need to add in order to appear correctly. Within WordPress, add the `wp-components` stylesheet as a dependency of your plugin's stylesheet. See [wp_enqueue_style documentation](https://developer.wordpress.org/reference/functions/wp_enqueue_style/#parameters) for how to specify dependencies. + +In non-WordPress projects, link to the `build-style/style.css` file directly, it is located at `node_modules/@wordpress/components/build-style/style.css`. <br/><br/><p align="center"><img src="https://s.w.org/style/images/codeispoetry.png?1" alt="Code is Poetry." /></p> diff --git a/packages/components/package.json b/packages/components/package.json index 56b8bd902e9dc1..4beac832581982 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/components", - "version": "9.2.4", + "version": "9.4.1", "description": "UI components for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -24,7 +24,7 @@ "build-style/**" ], "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@emotion/core": "^10.0.22", "@emotion/css": "^10.0.22", "@emotion/native": "^10.0.22", @@ -48,15 +48,15 @@ "downshift": "^4.0.5", "gradient-parser": "^0.1.5", "lodash": "^4.17.15", - "memize": "^1.0.5", + "memize": "^1.1.0", "moment": "^2.22.1", "re-resizable": "^6.0.0", "react-dates": "^17.1.1", "react-spring": "^8.0.20", - "reakit": "^1.0.0-beta.12", + "reakit": "^1.0.0-rc.0", "rememo": "^3.0.0", "tinycolor2": "^1.4.1", - "uuid": "^3.3.2" + "uuid": "^7.0.2" }, "publishConfig": { "access": "public" diff --git a/packages/components/src/angle-picker-control/stories/index.js b/packages/components/src/angle-picker-control/stories/index.js index 0c861f1b414d44..5d88c9be90d59c 100644 --- a/packages/components/src/angle-picker-control/stories/index.js +++ b/packages/components/src/angle-picker-control/stories/index.js @@ -9,7 +9,7 @@ import { useState } from '@wordpress/element'; import AnglePickerControl from '../'; export default { - title: 'Components|AnglePickerControl', + title: 'Components/AnglePickerControl', component: AnglePickerControl, }; diff --git a/packages/components/src/animate/style.scss b/packages/components/src/animate/style.scss index b6932156b244ac..1d64423e42f1f0 100644 --- a/packages/components/src/animate/style.scss +++ b/packages/components/src/animate/style.scss @@ -36,6 +36,10 @@ &.is-from-left { transform: translateX(+100%); } + + &.is-from-right { + transform: translateX(-100%); + } } @keyframes components-animate__slide-in-animation { diff --git a/packages/components/src/autocomplete/index.js b/packages/components/src/autocomplete/index.js index 6466328cabd836..8517c7bfc83e0b 100644 --- a/packages/components/src/autocomplete/index.js +++ b/packages/components/src/autocomplete/index.js @@ -227,6 +227,7 @@ export class Autocomplete extends Component { if ( !! filteredOptions.length ) { debouncedSpeak( sprintf( + /* translators: %d: number of results. */ _n( '%d result found, use up and down arrow keys to navigate.', '%d results found, use up and down arrow keys to navigate.', diff --git a/packages/components/src/button-group/index.js b/packages/components/src/button-group/index.js index 6f4fb672c8c6ef..2ef2b5e94c6018 100644 --- a/packages/components/src/button-group/index.js +++ b/packages/components/src/button-group/index.js @@ -3,10 +3,15 @@ */ import classnames from 'classnames'; -function ButtonGroup( { className, ...props } ) { +/** + * WordPress dependencies + */ +import { forwardRef } from '@wordpress/element'; + +function ButtonGroup( { className, ...props }, ref ) { const classes = classnames( 'components-button-group', className ); - return <div { ...props } className={ classes } role="group" />; + return <div ref={ ref } role="group" className={ classes } { ...props } />; } -export default ButtonGroup; +export default forwardRef( ButtonGroup ); diff --git a/packages/components/src/button/style.scss b/packages/components/src/button/style.scss index 2d0d325d6209f0..559d207972bb91 100644 --- a/packages/components/src/button/style.scss +++ b/packages/components/src/button/style.scss @@ -30,7 +30,7 @@ // Focus. // See https://github.com/WordPress/gutenberg/issues/13267 for more context on these selectors. &:focus:not(:disabled) { - box-shadow: 0 0 0 2px color($theme-color); + box-shadow: 0 0 0 $border-width-focus $theme-color; // Windows High Contrast mode will show this outline, but not the box-shadow. outline: 1px solid transparent; @@ -59,7 +59,7 @@ } &:focus:not(:disabled) { - box-shadow: inset 0 0 0 1px $white, 0 0 0 2px color($theme-color); + box-shadow: inset 0 0 0 1px $white, 0 0 0 $border-width-focus $theme-color; // Windows High Contrast mode will show this outline, but not the box-shadow. outline: 1px solid transparent; @@ -188,7 +188,7 @@ color: #124964; box-shadow: 0 0 0 $border-width #5b9dd9, - 0 0 2px $border-width rgba(30, 140, 190, 0.8); + 0 0 $border-width-focus $border-width rgba(30, 140, 190, 0.8); } } @@ -212,9 +212,18 @@ &.is-secondary.is-busy:disabled, &.is-secondary.is-busy[aria-disabled="true"] { animation: components-button__busy-animation 2500ms infinite linear; - background-size: 100px 100%; - background-image: repeating-linear-gradient(-45deg, $light-gray-500, $white 11px, $white 10px, $light-gray-500 20px); opacity: 1; + background-size: 100px 100%; + // Disable reason: This function call looks nicer when each argument is on its own line. + /* stylelint-disable */ + background-image: linear-gradient( + -45deg, + color($white shade(2%)) 28%, + color($white shade(12%)) 28%, + color($white shade(12%)) 72%, + color($white shade(2%)) 72% + ); + /* stylelint-enable */ } &.is-small { @@ -249,6 +258,23 @@ } } + // Toggled style. + &.is-pressed { + color: $white; + background: $dark-gray-primary; + + &:focus:not(:disabled) { + box-shadow: inset 0 0 0 1px $white, 0 0 0 $border-width-focus $theme-color; + + // Windows High Contrast mode will show this outline, but not the box-shadow. + outline: 2px solid transparent; + } + + &:hover:not(:disabled) { + background: $dark-gray-primary; + } + } + svg { fill: currentColor; outline: none; diff --git a/packages/components/src/card/styles/card-styles.js b/packages/components/src/card/styles/card-styles.js index 1afba2ab42f639..dfdeb37726db11 100644 --- a/packages/components/src/card/styles/card-styles.js +++ b/packages/components/src/card/styles/card-styles.js @@ -109,13 +109,13 @@ export function bodySize() { return ` &.is-size { &-large { - padding: 28px; + padding: 24px 32px; } &-medium { - padding: 20px; + padding: 16px 24px; } &-small { - padding: 12px; + padding: 16px; } &-extraSmall { padding: 8px; @@ -128,16 +128,16 @@ export function headerFooterSizes() { return ` &.is-size { &-large { - padding: 20px 28px; + padding: 24px 32px; } &-medium { - padding: 12px 20px; + padding: 16px 24px; } &-small { - padding: 8px 12px; + padding: 16px; } &-extraSmall { - padding: 4px 8px; + padding: 8px; } } `; diff --git a/packages/components/src/color-palette/test/__snapshots__/index.js.snap b/packages/components/src/color-palette/test/__snapshots__/index.js.snap index 760221f289041e..07eed8a9d5019f 100644 --- a/packages/components/src/color-palette/test/__snapshots__/index.js.snap +++ b/packages/components/src/color-palette/test/__snapshots__/index.js.snap @@ -367,9 +367,9 @@ exports[`ColorPalette should render a dynamic toolbar of colors 1`] = ` xmlns="http://www.w3.org/2000/svg" > <svg - aria-hidden="true" + aria-hidden={true} fill="#000000" - focusable="false" + focusable={false} height={24} role="img" viewBox="0 0 24 24" diff --git a/packages/components/src/color-picker/test/__snapshots__/index.js.snap b/packages/components/src/color-picker/test/__snapshots__/index.js.snap index 434ed647095fdb..ee3e5fc66b2a31 100644 --- a/packages/components/src/color-picker/test/__snapshots__/index.js.snap +++ b/packages/components/src/color-picker/test/__snapshots__/index.js.snap @@ -155,8 +155,8 @@ exports[`ColorPicker should commit changes to all views on blur 1`] = ` type="button" > <svg - aria-hidden="true" - focusable="false" + aria-hidden={true} + focusable={false} height={24} role="img" viewBox="0 0 24 24" @@ -329,8 +329,8 @@ exports[`ColorPicker should commit changes to all views on keyDown = DOWN 1`] = type="button" > <svg - aria-hidden="true" - focusable="false" + aria-hidden={true} + focusable={false} height={24} role="img" viewBox="0 0 24 24" @@ -503,8 +503,8 @@ exports[`ColorPicker should commit changes to all views on keyDown = ENTER 1`] = type="button" > <svg - aria-hidden="true" - focusable="false" + aria-hidden={true} + focusable={false} height={24} role="img" viewBox="0 0 24 24" @@ -677,8 +677,8 @@ exports[`ColorPicker should commit changes to all views on keyDown = UP 1`] = ` type="button" > <svg - aria-hidden="true" - focusable="false" + aria-hidden={true} + focusable={false} height={24} role="img" viewBox="0 0 24 24" @@ -851,8 +851,8 @@ exports[`ColorPicker should only update input view for draft changes 1`] = ` type="button" > <svg - aria-hidden="true" - focusable="false" + aria-hidden={true} + focusable={false} height={24} role="img" viewBox="0 0 24 24" @@ -1025,8 +1025,8 @@ exports[`ColorPicker should render color picker 1`] = ` type="button" > <svg - aria-hidden="true" - focusable="false" + aria-hidden={true} + focusable={false} height={24} role="img" viewBox="0 0 24 24" diff --git a/packages/components/src/custom-gradient-picker/control-points.js b/packages/components/src/custom-gradient-picker/control-points.js index b83093ef4475e1..7eaf9ecae250fe 100644 --- a/packages/components/src/custom-gradient-picker/control-points.js +++ b/packages/components/src/custom-gradient-picker/control-points.js @@ -214,7 +214,11 @@ export default function ControlPoints( { ) { return; } - onStartControlPointChange(); + if ( isOpen ) { + onStopControlPointChange(); + } else { + onStartControlPointChange(); + } onToggle(); } } onMouseDown={ () => { diff --git a/packages/components/src/custom-gradient-picker/custom-gradient-bar.js b/packages/components/src/custom-gradient-picker/custom-gradient-bar.js index 9b7a1a6527ada0..6bf81d83f0082a 100644 --- a/packages/components/src/custom-gradient-picker/custom-gradient-bar.js +++ b/packages/components/src/custom-gradient-picker/custom-gradient-bar.js @@ -51,8 +51,12 @@ function InsertPoint( { <Button aria-expanded={ isOpen } onClick={ () => { - setAlreadyInsertedPoint( false ); - onOpenInserter(); + if ( isOpen ) { + onCloseInserter(); + } else { + setAlreadyInsertedPoint( false ); + onOpenInserter(); + } onToggle(); } } className="components-custom-gradient-picker__insert-point" diff --git a/packages/components/src/custom-gradient-picker/stories/index.js b/packages/components/src/custom-gradient-picker/stories/index.js new file mode 100644 index 00000000000000..e34cc07531af02 --- /dev/null +++ b/packages/components/src/custom-gradient-picker/stories/index.js @@ -0,0 +1,29 @@ +/** + * WordPress dependencies + */ +import { useState } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import CustomGradientPicker from '../'; + +export default { + title: 'Components/CustomGradientPicker', + component: CustomGradientPicker, +}; + +const CustomGradientPickerWithState = ( props ) => { + const [ gradient, setGradient ] = useState(); + return ( + <CustomGradientPicker + { ...props } + value={ gradient } + onChange={ setGradient } + /> + ); +}; + +export const _default = () => { + return <CustomGradientPickerWithState />; +}; diff --git a/packages/components/src/custom-select-control/style.scss b/packages/components/src/custom-select-control/style.scss index 7fd5bcc382821a..cf49b4f24d7687 100644 --- a/packages/components/src/custom-select-control/style.scss +++ b/packages/components/src/custom-select-control/style.scss @@ -9,17 +9,17 @@ } .components-custom-select-control__button { - border: 1px solid $dark-gray-200; - border-radius: 4px; - color: $dark-gray-500; + border: 1px solid $medium-gray-text; + border-radius: $radius-block-ui; display: inline; min-height: 30px; min-width: 130px; position: relative; text-align: left; - &:focus { - border-color: $blue-medium-500; + &:focus:not(:disabled) { + border-color: $theme-color; + box-shadow: 0 0 0 ($border-width-focus - $border-width) $theme-color; } &-icon { @@ -32,7 +32,17 @@ } .components-custom-select-control__menu { - background: $white; + background-color: $white; + + // Show border around the dropdown menu when open. + &:focus { + // Block UI appearance. + border: $border-width solid $dark-gray-primary; + border-radius: $radius-block-ui; + outline: none; + transition: none; + } + max-height: 400px; min-width: 100%; overflow: auto; diff --git a/packages/components/src/date-time/style.scss b/packages/components/src/date-time/style.scss index c80ac572d6afe1..73d18df3688ae1 100644 --- a/packages/components/src/date-time/style.scss +++ b/packages/components/src/date-time/style.scss @@ -54,19 +54,35 @@ font-size: $default-font-size; } + // Seperate borders so that border respect border radius + .CalendarMonth_table { + border-collapse: separate; + border-spacing: 2px; + } + .CalendarDay { font-size: $default-font-size; - border: 1px solid transparent; + border: none; border-radius: $radius-round; text-align: center; + + &:focus { + box-shadow: inset 0 0 0 $border-width-focus theme(primary), inset 0 0 0 #{ $border-width-focus + $border-width } $white; + outline: 2px solid transparent; // Shown in Windows 10 high contrast mode. + } } .CalendarDay__selected { background: theme(primary); + border: 2px solid transparent; // This indicates selection in Windows 10 high contrast mode. &:hover { background: color(theme(primary) shade(15%)); } + + &:focus { + box-shadow: inset 0 0 0 $border-width $white; + } } .DayPickerNavigation_button__horizontalDefault { diff --git a/packages/components/src/date-time/test/__snapshots__/time.js.snap b/packages/components/src/date-time/test/__snapshots__/time.js.snap index e27e600f089f22..b65d4fddd151c0 100644 --- a/packages/components/src/date-time/test/__snapshots__/time.js.snap +++ b/packages/components/src/date-time/test/__snapshots__/time.js.snap @@ -317,7 +317,7 @@ exports[`TimePicker matches the snapshot when the is12hour prop is specified 1`] value="00" /> </div> - <ButtonGroup + <ForwardRef(ButtonGroup) className="components-datetime__time-field components-datetime__time-field-am-pm" > <ForwardRef(Button) @@ -336,7 +336,7 @@ exports[`TimePicker matches the snapshot when the is12hour prop is specified 1`] > PM </ForwardRef(Button)> - </ButtonGroup> + </ForwardRef(ButtonGroup)> </div> </fieldset> </div> @@ -498,7 +498,7 @@ exports[`TimePicker matches the snapshot when the is12hour prop is true 1`] = ` value="00" /> </div> - <ButtonGroup + <ForwardRef(ButtonGroup) className="components-datetime__time-field components-datetime__time-field-am-pm" > <ForwardRef(Button) @@ -517,7 +517,7 @@ exports[`TimePicker matches the snapshot when the is12hour prop is true 1`] = ` > PM </ForwardRef(Button)> - </ButtonGroup> + </ForwardRef(ButtonGroup)> </div> </fieldset> </div> diff --git a/packages/components/src/disabled/stories/index.js b/packages/components/src/disabled/stories/index.js new file mode 100644 index 00000000000000..527c76899c6527 --- /dev/null +++ b/packages/components/src/disabled/stories/index.js @@ -0,0 +1,31 @@ +/** + * Internal dependencies + */ +import Disabled from '../'; +import SelectControl from '../../select-control/'; +import TextControl from '../../text-control/'; +import TextareaControl from '../../textarea-control/'; + +export default { + title: 'Components/Disabled', + component: Disabled, +}; + +export const _default = () => { + return ( + <Disabled> + <TextControl label="Text Control" /> + <TextareaControl label="TextArea Control" /> + <SelectControl + label="Select Control" + onChange={ () => {} } + options={ [ + { value: null, label: 'Select an option', disabled: true }, + { value: 'a', label: 'Option A' }, + { value: 'b', label: 'Option B' }, + { value: 'c', label: 'Option C' }, + ] } + /> + </Disabled> + ); +}; diff --git a/packages/components/src/dropdown-menu/index.native.js b/packages/components/src/dropdown-menu/index.native.js index 6243847023227e..d665e37e49cae3 100644 --- a/packages/components/src/dropdown-menu/index.native.js +++ b/packages/components/src/dropdown-menu/index.native.js @@ -1,5 +1,184 @@ -function DropdownMenu() { - return null; +/** + * External dependencies + */ +import classnames from 'classnames'; +import { flatMap, isEmpty, isFunction } from 'lodash'; +import { Platform } from 'react-native'; +/** + * WordPress dependencies + */ +import { DOWN } from '@wordpress/keycodes'; +import deprecated from '@wordpress/deprecated'; +import { BottomSheet, PanelBody } from '@wordpress/components'; +import { withPreferredColorScheme } from '@wordpress/compose'; + +/** + * Internal dependencies + */ +import Button from '../button'; +import Dropdown from '../dropdown'; + +function mergeProps( defaultProps = {}, props = {} ) { + const mergedProps = { + ...defaultProps, + ...props, + }; + + if ( props.className && defaultProps.className ) { + mergedProps.className = classnames( + props.className, + defaultProps.className + ); + } + + return mergedProps; +} + +function DropdownMenu( { + children, + className, + controls, + icon = 'menu', + label, + popoverProps, + toggleProps, + // The following props exist for backward compatibility. + menuLabel, + position, +} ) { + if ( menuLabel ) { + deprecated( '`menuLabel` prop in `DropdownComponent`', { + alternative: '`menuProps` object and its `aria-label` property', + plugin: 'Gutenberg', + } ); + } + + if ( position ) { + deprecated( '`position` prop in `DropdownComponent`', { + alternative: '`popoverProps` object and its `position` property', + plugin: 'Gutenberg', + } ); + } + + if ( isEmpty( controls ) && ! isFunction( children ) ) { + return null; + } + + // Normalize controls to nested array of objects (sets of controls) + let controlSets; + if ( ! isEmpty( controls ) ) { + controlSets = controls; + if ( ! Array.isArray( controlSets[ 0 ] ) ) { + controlSets = [ controlSets ]; + } + } + const mergedPopoverProps = mergeProps( + { + className: 'components-dropdown-menu__popover', + position, + }, + popoverProps + ); + + return ( + <Dropdown + className={ classnames( 'components-dropdown-menu', className ) } + popoverProps={ mergedPopoverProps } + renderToggle={ ( { isOpen, onToggle } ) => { + const openOnArrowDown = ( event ) => { + if ( ! isOpen && event.keyCode === DOWN ) { + event.preventDefault(); + event.stopPropagation(); + onToggle(); + } + }; + const mergedToggleProps = mergeProps( + { + className: classnames( + 'components-dropdown-menu__toggle', + { + 'is-opened': isOpen, + } + ), + }, + toggleProps + ); + + return ( + <Button + { ...mergedToggleProps } + icon={ icon } + onClick={ ( event ) => { + onToggle( event ); + if ( mergedToggleProps.onClick ) { + mergedToggleProps.onClick( event ); + } + } } + onKeyDown={ ( event ) => { + openOnArrowDown( event ); + if ( mergedToggleProps.onKeyDown ) { + mergedToggleProps.onKeyDown( event ); + } + } } + aria-haspopup="true" + aria-expanded={ isOpen } + label={ label } + showTooltip + > + { mergedToggleProps.children } + </Button> + ); + } } + renderContent={ ( { isOpen, onClose, ...props } ) => { + return ( + <BottomSheet + hideHeader={ true } + isVisible={ isOpen } + onClose={ onClose } + > + { isFunction( children ) ? children( props ) : null } + <PanelBody + title={ label } + style={ { paddingLeft: 0, paddingRight: 0 } } + > + { flatMap( + controlSets, + ( controlSet, indexOfSet ) => + controlSet.map( + ( control, indexOfControl ) => ( + <BottomSheet.Cell + key={ [ + indexOfSet, + indexOfControl, + ].join() } + label={ control.title } + onPress={ () => { + onClose(); + if ( control.onClick ) { + control.onClick(); + } + } } + editable={ false } + icon={ control.icon } + leftAlign={ true } + isSelected={ control.isActive } + separatorType={ + indexOfControl === + controlSet.length - 1 || + Platform.OS === 'android' + ? 'none' + : 'leftMargin' + } + /> + ) + ) + ) } + </PanelBody> + </BottomSheet> + ); + } } + /> + ); } -export default DropdownMenu; +export default withPreferredColorScheme( DropdownMenu ); diff --git a/packages/components/src/dropdown-menu/stories/index.js b/packages/components/src/dropdown-menu/stories/index.js new file mode 100644 index 00000000000000..0c29e016aacf2d --- /dev/null +++ b/packages/components/src/dropdown-menu/stories/index.js @@ -0,0 +1,27 @@ +/** + * External dependencies + */ +import { text, object } from '@storybook/addon-knobs'; + +/** + * Internal dependencies + */ +import DropdownMenu from '../'; + +export default { title: 'Components/DropdownMenu', component: DropdownMenu }; + +export const _default = () => { + const label = text( 'Label', 'Select a direction.' ); + const icon = text( 'Icon', 'ellipsis' ); + const controls = object( 'Controls', [ + { + title: 'Up', + icon: 'arrow-up', + }, + { + title: 'Down', + icon: 'arrow-down', + }, + ] ); + return <DropdownMenu icon={ icon } label={ label } controls={ controls } />; +}; diff --git a/packages/components/src/dropdown-menu/style.scss b/packages/components/src/dropdown-menu/style.scss index c69ecd8c80a8dd..8b6c26be120168 100644 --- a/packages/components/src/dropdown-menu/style.scss +++ b/packages/components/src/dropdown-menu/style.scss @@ -34,20 +34,19 @@ height: 1px; } - &.is-active { + &.is-active svg { // Block UI appearance. - border: $border-width solid $dark-gray-primary; - border-radius: $radius-block-ui; color: $white; background: $dark-gray-primary; + box-shadow: 0 0 0 $border-width $dark-gray-primary; + border-radius: $border-width; } // Formatting buttons > svg { - border-radius: $radius-round-rectangle; + border-radius: $radius-block-ui; width: $button-size-small; height: $button-size-small; - margin: -1px $grid-unit-10 -1px 0; } } diff --git a/packages/components/src/dropdown/index.js b/packages/components/src/dropdown/index.js index cf47a7ac188a4a..dbf8380b1ffa47 100644 --- a/packages/components/src/dropdown/index.js +++ b/packages/components/src/dropdown/index.js @@ -78,7 +78,7 @@ class Dropdown extends Component { const { renderContent, renderToggle, - position = 'bottom', + position = 'bottom right', className, contentClassName, expandOnMobile, diff --git a/packages/components/src/form-toggle/stories/index.js b/packages/components/src/form-toggle/stories/index.js new file mode 100644 index 00000000000000..5f4f86a82034d6 --- /dev/null +++ b/packages/components/src/form-toggle/stories/index.js @@ -0,0 +1,28 @@ +/** + * WordPress dependencies + */ +import { useState } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import FormToggle from '../'; + +export default { title: 'Components/FormToggle', component: FormToggle }; + +const FormToggleWithState = ( { checked, ...props } ) => { + const [ isChecked, setChecked ] = useState( checked ); + return ( + <FormToggle + { ...props } + checked={ isChecked } + onChange={ () => { + setChecked( ! isChecked ); + } } + /> + ); +}; + +export const _default = () => { + return <FormToggleWithState checked />; +}; diff --git a/packages/components/src/form-toggle/style.scss b/packages/components/src/form-toggle/style.scss index ebe43dc70441a6..8be2aa6655ea98 100644 --- a/packages/components/src/form-toggle/style.scss +++ b/packages/components/src/form-toggle/style.scss @@ -77,7 +77,11 @@ $toggle-border-width: 2px; } &__input:focus + .components-form-toggle__track { - @include switch-style__focus-active(); + box-shadow: 0 0 0 2px $white, 0 0 0 (2px + $border-width-focus) $theme-color; + + // Windows High Contrast mode will show this outline, but not the box-shadow. + outline: 2px solid transparent; + outline-offset: 2px; } &.is-checked { diff --git a/packages/components/src/form-token-field/index.js b/packages/components/src/form-token-field/index.js index b2c81977a50fbc..0641a327c64734 100644 --- a/packages/components/src/form-token-field/index.js +++ b/packages/components/src/form-token-field/index.js @@ -514,6 +514,7 @@ class FormTokenField extends Component { const message = hasMatchingSuggestions ? sprintf( + /* translators: %d: number of results. */ _n( '%d result found, use up and down arrow keys to navigate.', '%d results found, use up and down arrow keys to navigate.', diff --git a/packages/components/src/gradient-picker/stories/index.js b/packages/components/src/gradient-picker/stories/index.js new file mode 100644 index 00000000000000..30d719ce4bec35 --- /dev/null +++ b/packages/components/src/gradient-picker/stories/index.js @@ -0,0 +1,83 @@ +/** + * External dependencies + */ +import { text, boolean, object } from '@storybook/addon-knobs'; + +/** + * WordPress dependencies + */ +import { useState } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import GradientPicker from '../'; + +export default { + title: 'Components/GradientPicker', + component: GradientPicker, +}; + +const GradientPickerWithState = ( props ) => { + const [ gradient, setGradient ] = useState(); + return ( + <GradientPicker + { ...props } + value={ gradient } + onChange={ setGradient } + /> + ); +}; + +export const _default = () => { + const disableCustomGradients = boolean( 'Disable Custom Gradients', false ); + const clearable = boolean( 'Clearable', true ); + const className = text( 'Class Name', '' ); + const gradients = object( 'Gradients', [ + { + name: 'Vivid cyan blue to vivid purple', + gradient: + 'linear-gradient(135deg,rgba(6,147,227,1) 0%,rgb(155,81,224) 100%)', + slug: 'vivid-cyan-blue-to-vivid-purple', + }, + { + name: 'Light green cyan to vivid green cyan', + gradient: + 'linear-gradient(135deg,rgb(122,220,180) 0%,rgb(0,208,130) 100%)', + slug: 'light-green-cyan-to-vivid-green-cyan', + }, + { + name: 'Luminous vivid amber to luminous vivid orange', + gradient: + 'linear-gradient(135deg,rgba(252,185,0,1) 0%,rgba(255,105,0,1) 100%)', + slug: 'luminous-vivid-amber-to-luminous-vivid-orange', + }, + { + name: 'Luminous vivid orange to vivid red', + gradient: + 'linear-gradient(135deg,rgba(255,105,0,1) 0%,rgb(207,46,46) 100%)', + slug: 'luminous-vivid-orange-to-vivid-red', + }, + { + name: 'Very light gray to cyan bluish gray', + gradient: + 'linear-gradient(135deg,rgb(238,238,238) 0%,rgb(169,184,195) 100%)', + slug: 'very-light-gray-to-cyan-bluish-gray', + }, + { + name: 'Cool to warm spectrum', + gradient: + 'linear-gradient(135deg,rgb(74,234,220) 0%,rgb(151,120,209) 20%,rgb(207,42,186) 40%,rgb(238,44,130) 60%,rgb(251,105,98) 80%,rgb(254,248,76) 100%)', + slug: 'cool-to-warm-spectrum', + }, + ] ); + + return ( + <GradientPickerWithState + disableCustomGradients={ disableCustomGradients } + gradients={ gradients } + clearable={ clearable } + className={ className } + /> + ); +}; diff --git a/packages/components/src/guide/finish-button.js b/packages/components/src/guide/finish-button.js index 151fd3a9672ccd..d6ee4ad552b069 100644 --- a/packages/components/src/guide/finish-button.js +++ b/packages/components/src/guide/finish-button.js @@ -14,7 +14,10 @@ export default function FinishButton( { className, onClick, children } ) { // Focus the button on mount if nothing else is focused. This prevents a // focus loss when the 'Next' button is swapped out. useLayoutEffect( () => { - if ( document.activeElement === document.body ) { + if ( + ! document.activeElement || + document.activeElement === document.body + ) { button.current.focus(); } }, [ button ] ); diff --git a/packages/components/src/guide/page-control.js b/packages/components/src/guide/page-control.js index 837a0b31e7d5ad..1a39fdd1426c8e 100644 --- a/packages/components/src/guide/page-control.js +++ b/packages/components/src/guide/page-control.js @@ -37,8 +37,8 @@ export default function PageControl( { isSelected={ page === currentPage } /> } - /* translators: %1$d: current page number %2$d: total number of pages */ aria-label={ sprintf( + /* translators: 1: current page number 2: total number of pages */ __( 'Page %1$d of %2$d' ), page + 1, numberOfPages diff --git a/packages/components/src/higher-order/with-focus-return/test/index.js b/packages/components/src/higher-order/with-focus-return/test/index.js index cd110d4fa7cd8e..67502237260b32 100644 --- a/packages/components/src/higher-order/with-focus-return/test/index.js +++ b/packages/components/src/higher-order/with-focus-return/test/index.js @@ -2,12 +2,12 @@ * External dependencies */ import renderer from 'react-test-renderer'; -import { mount } from 'enzyme'; +import { render } from '@testing-library/react'; /** * WordPress dependencies */ -import { Component, createElement } from '@wordpress/element'; +import { Component } from '@wordpress/element'; /** * Internal dependencies @@ -29,12 +29,8 @@ describe( 'withFocusReturn()', () => { const Composite = withFocusReturn( Test ); const activeElement = document.createElement( 'button' ); const switchFocusTo = document.createElement( 'input' ); - - const getInstance = ( wrapper ) => { - return wrapper.root.find( - ( node ) => node.instance instanceof Component - ).instance; - }; + document.body.appendChild( activeElement ); + document.body.appendChild( switchFocusTo ); beforeEach( () => { activeElement.focus(); @@ -74,72 +70,78 @@ describe( 'withFocusReturn()', () => { } ); it( 'should not switch focus back to the bound focus element', () => { - const mountedComposite = renderer.create( <Composite /> ); - - expect( getInstance( mountedComposite ).activeElementOnMount ).toBe( - activeElement - ); + const { unmount } = render( <Composite />, { + container: document.body.appendChild( + document.createElement( 'div' ) + ), + } ); // Change activeElement. switchFocusTo.focus(); expect( document.activeElement ).toBe( switchFocusTo ); // Should keep focus on switchFocusTo, because it is not within HOC. - mountedComposite.unmount(); + unmount(); expect( document.activeElement ).toBe( switchFocusTo ); } ); it( 'should switch focus back when unmounted while having focus', () => { - const wrapper = mount( <Composite /> ); - wrapper - .find( 'textarea' ) - .at( 0 ) - .simulate( 'focus' ); + const { container, unmount } = render( <Composite />, { + container: document.body.appendChild( + document.createElement( 'div' ) + ), + } ); + + const textarea = container.querySelector( 'textarea' ); + textarea.focus(); + expect( document.activeElement ).toBe( textarea ); // Should return to the activeElement saved with this component. - wrapper.unmount(); + unmount(); expect( document.activeElement ).toBe( activeElement ); } ); it( 'should switch focus to the most recent still-available focus target', () => { - const container = document.createElement( 'div' ); - document.body.appendChild( container ); - const wrapper = mount( - createElement( - ( props ) => ( - <Provider> - <input name="first" /> - { props.renderSecondInput && ( - <input name="second" /> - ) } - { props.renderComposite && <Composite /> } - </Provider> + const TestComponent = ( props ) => ( + <Provider> + <input name="first" /> + { props.renderSecondInput && <input name="second" /> } + { props.renderComposite && <Composite /> } + </Provider> + ); + + const { container, rerender } = render( + <TestComponent renderSecondInput />, + { + container: document.body.appendChild( + document.createElement( 'div' ) ), - { renderSecondInput: true } - ), - { attachTo: container } + } ); - function focus( selector ) { - const childWrapper = wrapper.find( selector ); - const childNode = childWrapper.getDOMNode(); - childWrapper.simulate( 'focus', { target: childNode } ); - } + const firstInput = container.querySelector( 'input[name="first"]' ); + firstInput.focus(); - focus( 'input[name="first"]' ); - jest.spyOn( - wrapper.find( 'input[name="first"]' ).getDOMNode(), - 'focus' + const secondInput = container.querySelector( + 'input[name="second"]' ); - focus( 'input[name="second"]' ); - wrapper.setProps( { renderComposite: true } ); - focus( 'textarea' ); - wrapper.setProps( { renderSecondInput: false } ); - wrapper.setProps( { renderComposite: false } ); - - expect( - wrapper.find( 'input[name="first"]' ).getDOMNode().focus - ).toHaveBeenCalled(); + secondInput.focus(); + + expect( document.activeElement ).toBe( secondInput ); + + rerender( <TestComponent renderSecondInput renderComposite /> ); + const textarea = container.querySelector( 'textarea' ); + textarea.focus(); + + expect( document.activeElement ).toBe( textarea ); + + rerender( <TestComponent renderComposite /> ); + + expect( document.activeElement ).toBe( textarea ); + + rerender( <TestComponent /> ); + + expect( document.activeElement ).toBe( firstInput ); } ); } ); } ); diff --git a/packages/components/src/higher-order/with-notices/index.js b/packages/components/src/higher-order/with-notices/index.js index 4806d6d8d6254c..0a1280438282cb 100644 --- a/packages/components/src/higher-order/with-notices/index.js +++ b/packages/components/src/higher-order/with-notices/index.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import uuid from 'uuid/v4'; +import { v4 as uuid } from 'uuid'; /** * WordPress dependencies diff --git a/packages/components/src/index.js b/packages/components/src/index.js index e02dde7f7217df..f5142afb2f86e0 100644 --- a/packages/components/src/index.js +++ b/packages/components/src/index.js @@ -62,6 +62,7 @@ export { default as Modal } from './modal'; export { default as ScrollLock } from './scroll-lock'; export { NavigableMenu, TabbableContainer } from './navigable-container'; export { default as Notice } from './notice'; +export { default as __experimentalNumberControl } from './number-control'; export { default as NoticeList } from './notice/list'; export { default as Panel } from './panel'; export { default as PanelBody } from './panel/body'; @@ -70,6 +71,8 @@ export { default as PanelRow } from './panel/row'; export { default as Placeholder } from './placeholder'; export { default as Popover } from './popover'; export { default as QueryControls } from './query-controls'; +export { default as __experimentalRadio } from './radio'; +export { default as __experimentalRadioGroup } from './radio-group'; export { default as RadioControl } from './radio-control'; export { default as RangeControl } from './range-control'; export { default as ResizableBox } from './resizable-box'; @@ -80,6 +83,7 @@ export { default as Snackbar } from './snackbar'; export { default as SnackbarList } from './snackbar/list'; export { default as Spinner } from './spinner'; export { default as TabPanel } from './tab-panel'; +export { default as __experimentalText } from './text'; export { default as TextControl } from './text-control'; export { default as TextareaControl } from './textarea-control'; export { default as TextHighlight } from './text-highlight'; @@ -91,6 +95,7 @@ export { default as ToolbarGroup } from './toolbar-group'; export { default as __experimentalToolbarItem } from './toolbar-item'; export { default as Tooltip } from './tooltip'; export { default as TreeSelect } from './tree-select'; +export { default as __experimentalUnitControl } from './unit-control'; export { default as VisuallyHidden } from './visually-hidden'; export { default as IsolatedEventContainer } from './isolated-event-container'; export { @@ -113,4 +118,3 @@ export { } from './higher-order/with-focus-return'; export { default as withNotices } from './higher-order/with-notices'; export { default as withSpokenMessages } from './higher-order/with-spoken-messages'; -export * from './text'; diff --git a/packages/components/src/index.native.js b/packages/components/src/index.native.js index abb7b278dc5723..5e213eddb10baa 100644 --- a/packages/components/src/index.native.js +++ b/packages/components/src/index.native.js @@ -30,6 +30,7 @@ export { default as TextareaControl } from './textarea-control'; export { default as PanelBody } from './panel/body'; export { default as PanelActions } from './panel/actions'; export { default as Button } from './button'; +export { default as __experimentalText } from './text'; export { default as TextControl } from './text-control'; export { default as ToggleControl } from './toggle-control'; export { default as SelectControl } from './select-control'; @@ -46,6 +47,7 @@ export { default as withFocusOutside } from './higher-order/with-focus-outside'; export { default as withFocusReturn } from './higher-order/with-focus-return'; export { default as withNotices } from './higher-order/with-notices'; export { default as withSpokenMessages } from './higher-order/with-spoken-messages'; +export * from './text'; // Mobile Components export { default as BottomSheet } from './mobile/bottom-sheet'; @@ -55,7 +57,6 @@ export { default as KeyboardAwareFlatList } from './mobile/keyboard-aware-flat-l export { default as ModalHeaderBar } from './mobile/modal-header-bar'; export { default as Picker } from './mobile/picker'; export { default as ReadableContentView } from './mobile/readable-content-view'; -export { default as StepperControl } from './mobile/stepper-control'; export { default as CycleSelectControl } from './mobile/cycle-select-control'; export { default as ImageWithFocalPoint } from './mobile/image-with-focalpoint'; export { default as LinearGradient } from './mobile/linear-gradient'; diff --git a/packages/components/src/mobile/bottom-sheet/cell.native.js b/packages/components/src/mobile/bottom-sheet/cell.native.js index 37228c481eb59f..50d11a85017151 100644 --- a/packages/components/src/mobile/bottom-sheet/cell.native.js +++ b/packages/components/src/mobile/bottom-sheet/cell.native.js @@ -9,12 +9,13 @@ import { I18nManager, AccessibilityInfo, } from 'react-native'; -import { isEmpty } from 'lodash'; +import { isEmpty, get } from 'lodash'; /** * WordPress dependencies */ import { Icon } from '@wordpress/components'; +import { check } from '@wordpress/icons'; import { Component } from '@wordpress/element'; import { __, _x, sprintf } from '@wordpress/i18n'; import { withPreferredColorScheme } from '@wordpress/compose'; @@ -87,6 +88,7 @@ class BottomSheetCell extends Component { accessibilityHint, accessibilityRole, disabled = false, + activeOpacity, onPress, label, value, @@ -98,8 +100,10 @@ class BottomSheetCell extends Component { cellContainerStyle = {}, cellRowContainerStyle = {}, onChangeValue, + onSubmit, children, editable = true, + isSelected = false, separatorType, style = {}, getStylesFromColorScheme, @@ -127,7 +131,7 @@ class BottomSheetCell extends Component { ? cellLabelLeftAlignNoIconStyle : cellLabelCenteredStyle; const defaultLabelStyle = - showValue || icon !== undefined || customActionButton + showValue || customActionButton || icon ? cellLabelStyle : defaultMissingIconAndValue; @@ -226,6 +230,7 @@ class BottomSheetCell extends Component { } onFocus={ startEditing } onBlur={ finishEditing } + onSubmitEditing={ onSubmit } keyboardType={ this.typeToKeyboardType( type, step ) } { ...valueProps } /> @@ -271,6 +276,11 @@ class BottomSheetCell extends Component { this.state.isScreenReaderEnabled && accessible ? 'none' : 'auto'; const { title, handler } = customActionButton || {}; + const opacity = + activeOpacity !== undefined + ? activeOpacity + : get( platformStyles, 'activeOpacity.opacity' ); + return ( <TouchableOpacity accessible={ @@ -287,6 +297,7 @@ class BottomSheetCell extends Component { : accessibilityHint } disabled={ disabled } + activeOpacity={ opacity } onPress={ onCellPress } style={ [ styles.clipToBounds, style ] } > @@ -303,6 +314,7 @@ class BottomSheetCell extends Component { icon={ icon } size={ 24 } color={ iconStyle.color } + isPressed={ false } /> <View style={ @@ -326,6 +338,12 @@ class BottomSheetCell extends Component { </TouchableOpacity> ) } </View> + { isSelected && ( + <Icon + icon={ check } + fill={ platformStyles.isSelected.color } + /> + ) } { showValue && getValueComponent() } { children } </View> diff --git a/packages/components/src/mobile/bottom-sheet/cellStyles.android.scss b/packages/components/src/mobile/bottom-sheet/cellStyles.android.scss index 4feb815ba9bd07..0c823db8c3fc90 100644 --- a/packages/components/src/mobile/bottom-sheet/cellStyles.android.scss +++ b/packages/components/src/mobile/bottom-sheet/cellStyles.android.scss @@ -5,3 +5,7 @@ .separatorMarginLeft { margin-left: 56px; } + +.isSelected { + color: $blue-wordpress; +} diff --git a/packages/components/src/mobile/bottom-sheet/cellStyles.ios.scss b/packages/components/src/mobile/bottom-sheet/cellStyles.ios.scss index 45b97213d1768f..6cb9dead68b6f7 100644 --- a/packages/components/src/mobile/bottom-sheet/cellStyles.ios.scss +++ b/packages/components/src/mobile/bottom-sheet/cellStyles.ios.scss @@ -5,3 +5,11 @@ .separatorMarginLeft { margin-left: 36px; } + +.isSelected { + color: $blue-wordpress; +} + +.activeOpacity { + opacity: 1; +} diff --git a/packages/components/src/mobile/bottom-sheet/index.native.js b/packages/components/src/mobile/bottom-sheet/index.native.js index e04cf3970f2d96..7ad5917a33bd77 100644 --- a/packages/components/src/mobile/bottom-sheet/index.native.js +++ b/packages/components/src/mobile/bottom-sheet/index.native.js @@ -17,6 +17,7 @@ import SafeArea from 'react-native-safe-area'; /** * WordPress dependencies */ +import { subscribeAndroidModalClosed } from '@wordpress/react-native-bridge'; import { Component } from '@wordpress/element'; import { withPreferredColorScheme } from '@wordpress/compose'; @@ -69,6 +70,14 @@ class BottomSheet extends Component { } componentDidMount() { + if ( Platform.OS === 'android' ) { + this.androidModalClosedSubscription = subscribeAndroidModalClosed( + () => { + this.props.onClose(); + } + ); + } + this.keyboardWillShowListener = Keyboard.addListener( 'keyboardWillShow', this.keyboardWillShow @@ -87,6 +96,9 @@ class BottomSheet extends Component { } componentWillUnmount() { + if ( this.androidModalClosedSubscription ) { + this.androidModalClosedSubscription.remove(); + } if ( this.safeAreaEventSubscription === null ) { return; } diff --git a/packages/components/src/mobile/bottom-sheet/range-cell.native.js b/packages/components/src/mobile/bottom-sheet/range-cell.native.js index 717ab84232a097..96867a38630719 100644 --- a/packages/components/src/mobile/bottom-sheet/range-cell.native.js +++ b/packages/components/src/mobile/bottom-sheet/range-cell.native.js @@ -133,6 +133,7 @@ class BottomSheetRangeCell extends Component { } announceCurrentValue( value ) { + /* translators: %s: current cell value. */ const announcement = sprintf( __( 'Current value is %s' ), value ); AccessibilityInfo.announceForAccessibility( announcement ); } @@ -182,6 +183,7 @@ class BottomSheetRangeCell extends Component { accessibilityRole={ 'none' } value={ '' } editable={ false } + activeOpacity={ 1 } accessible={ accessible } onPress={ this.onCellPress } accessibilityLabel={ accessibilityLabel } diff --git a/packages/components/src/mobile/bottom-sheet/stepper-cell/stepper.ios.js b/packages/components/src/mobile/bottom-sheet/stepper-cell/stepper.ios.js index a688bd46dc5c9a..e226b8adb4b20f 100644 --- a/packages/components/src/mobile/bottom-sheet/stepper-cell/stepper.ios.js +++ b/packages/components/src/mobile/bottom-sheet/stepper-cell/stepper.ios.js @@ -49,12 +49,7 @@ function Stepper( { onPressOut={ onPressOut } style={ [ buttonStyle, isMaxValue ? { opacity: 0.4 } : null ] } > - <Icon - icon={ plus } - size={ 24 } - color={ buttonStyle.color } - style={ styles.plus } - /> + <Icon icon={ plus } size={ 24 } color={ buttonStyle.color } /> </TouchableOpacity> </View> ); diff --git a/packages/components/src/mobile/bottom-sheet/stepper-cell/style.native.scss b/packages/components/src/mobile/bottom-sheet/stepper-cell/style.native.scss index d728d79909e507..597bb22dc726e7 100644 --- a/packages/components/src/mobile/bottom-sheet/stepper-cell/style.native.scss +++ b/packages/components/src/mobile/bottom-sheet/stepper-cell/style.native.scss @@ -64,8 +64,3 @@ .valueTextDark { color: $light-opacity-200; } - -.plus { - margin-top: 4px; - margin-right: 1px; -} diff --git a/packages/components/src/mobile/bottom-sheet/styles.native.scss b/packages/components/src/mobile/bottom-sheet/styles.native.scss index 254817bfb44490..4550fb21d0c52d 100644 --- a/packages/components/src/mobile/bottom-sheet/styles.native.scss +++ b/packages/components/src/mobile/bottom-sheet/styles.native.scss @@ -93,6 +93,7 @@ flex-direction: row; min-height: 48; align-items: center; + justify-content: space-between; } .clipToBounds { @@ -137,7 +138,7 @@ font-size: 17px; color: #2e4453; flex: 1; - margin-left: 12px; + margin-left: 0; } .cellValue { diff --git a/packages/components/src/mobile/image-with-focalpoint/index.native.js b/packages/components/src/mobile/image-with-focalpoint/index.native.js index 0e542eaad82770..440b8477ff2bcd 100644 --- a/packages/components/src/mobile/image-with-focalpoint/index.native.js +++ b/packages/components/src/mobile/image-with-focalpoint/index.native.js @@ -27,7 +27,7 @@ const ImageWithFocalPoint = ( { focalPoint, url } ) => { } ); } ); } - }, [] ); + }, [ url ] ); const onContainerLayout = ( event ) => { const { height, width } = event.nativeEvent.layout; @@ -97,18 +97,10 @@ const ImageWithFocalPoint = ( { focalPoint, url } ) => { return ( <View style={ styles.container } onLayout={ onContainerLayout }> <Image - aspectRatio={ - originalImageData - ? originalImageData.aspectRatio - : undefined - } + aspectRatio={ originalImageData?.aspectRatio } style={ [ styles.image, - { - height: containerSize - ? containerSize.height - : undefined, - }, + { height: containerSize?.height }, getImageStyles(), ] } source={ { uri: url } } diff --git a/packages/components/src/mobile/keyboard-aware-flat-list/index.ios.js b/packages/components/src/mobile/keyboard-aware-flat-list/index.ios.js index 83f8f64f84ff64..932e54646a9afe 100644 --- a/packages/components/src/mobile/keyboard-aware-flat-list/index.ios.js +++ b/packages/components/src/mobile/keyboard-aware-flat-list/index.ios.js @@ -50,6 +50,7 @@ export const KeyboardAwareFlatList = ( { onKeyboardWillShow={ () => { this.keyboardWillShowIndicator = true; } } + scrollEnabled={ listProps.scrollEnabled } onScroll={ ( event ) => { this.latestContentOffsetY = event.nativeEvent.contentOffset.y; } } diff --git a/packages/components/src/mobile/modal-header-bar/styles.native.scss b/packages/components/src/mobile/modal-header-bar/styles.native.scss index 0697ff71e7e55e..4ee1ebe584704d 100644 --- a/packages/components/src/mobile/modal-header-bar/styles.native.scss +++ b/packages/components/src/mobile/modal-header-bar/styles.native.scss @@ -56,5 +56,5 @@ } .separatorDark { - background-color: $gray-70; + background-color: #2d2d2d; } diff --git a/packages/components/src/mobile/readable-content-view/index.native.js b/packages/components/src/mobile/readable-content-view/index.native.js index a25048b0b5dffa..ec1f67a4d98f89 100644 --- a/packages/components/src/mobile/readable-content-view/index.native.js +++ b/packages/components/src/mobile/readable-content-view/index.native.js @@ -8,14 +8,15 @@ import { View, Dimensions } from 'react-native'; */ import styles from './style.scss'; -const ReadableContentView = ( { reversed, children } ) => ( +const ReadableContentView = ( { reversed, children, style } ) => ( <View style={ styles.container }> <View - style={ + style={ [ reversed ? styles.reversedCenteredContent - : styles.centeredContent - } + : styles.centeredContent, + style, + ] } > { children } </View> diff --git a/packages/components/src/mobile/stepper-control/README.md b/packages/components/src/mobile/stepper-control/README.md deleted file mode 100644 index f66bce6171fc2f..00000000000000 --- a/packages/components/src/mobile/stepper-control/README.md +++ /dev/null @@ -1,69 +0,0 @@ -# StepperControl - -`StepperControl` shows a stepper control to change a value wrapped in a `StepperCell` component. - -## Usage - -Usage example - -```jsx -import { StepperControl } from '@wordpress/components'; -import { more } from '@wordpress/icons'; - -function Stepper( { onChange, value } ) { - return ( - <StepperControl - icon={ more } - label="Columns" - max={ 8 } - min={ 1 } - onChange={ onChange } - value={ value } - /> - ); -} -``` - -## Props - -### max - -Maximum value of the stepper. - -- Type: `Number` -- Required: Yes -- Platform: Mobile - -### min - -Minimum value of the stepper. - -- Type: `Number` -- Required: Yes -- Platform: Mobile - -### step - -Step increment value. - -- Type: `Number` -- Required: No -- Platform: Mobile - -### value - -Current value of the stepper. - -- Type: `Number` -- Required: Yes -- Platform: Mobile - -### onChange - -Callback called when the value has changed - -- Type: `Function` -- Required: Yes -- Platform: Mobile - -The argument of the callback is the updated value as a `Number`. diff --git a/packages/components/src/mobile/stepper-control/index.native.js b/packages/components/src/mobile/stepper-control/index.native.js deleted file mode 100644 index 5cc565f3937824..00000000000000 --- a/packages/components/src/mobile/stepper-control/index.native.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Internal dependencies - */ -import StepperCell from '../bottom-sheet/stepper-cell'; - -function StepperControl( { - icon, - label, - max, - min, - onChange, - separatorType, - step, - value, -} ) { - return ( - <StepperCell - icon={ icon } - label={ label } - max={ max } - min={ min } - onChange={ onChange } - separatorType={ separatorType } - step={ step } - value={ value } - /> - ); -} - -export default StepperControl; diff --git a/packages/components/src/navigable-container/test/menu.js b/packages/components/src/navigable-container/test/menu.js index eed4b235c91b4c..97609943740b80 100644 --- a/packages/components/src/navigable-container/test/menu.js +++ b/packages/components/src/navigable-container/test/menu.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { mount } from 'enzyme'; +import { fireEvent, render } from '@testing-library/react'; import { each } from 'lodash'; /** @@ -14,8 +14,8 @@ import { UP, DOWN, LEFT, RIGHT, SPACE } from '@wordpress/keycodes'; */ import { NavigableMenu } from '../menu'; -function simulateVisible( wrapper, selector ) { - const elements = wrapper.getDOMNode().querySelectorAll( selector ); +function simulateVisible( container, selector ) { + const elements = container.querySelectorAll( selector ); each( elements, ( elem ) => { elem.getClientRects = () => [ 'trick-jsdom-into-having-size-for-element-rect', @@ -23,7 +23,7 @@ function simulateVisible( wrapper, selector ) { } ); } -function fireKeyDown( container, keyCode, shiftKey ) { +function fireKeyDown( node, keyCode, shiftKey ) { const interaction = { stopped: false, }; @@ -35,7 +35,7 @@ function fireKeyDown( container, keyCode, shiftKey ) { event.stopImmediatePropagation = () => { interaction.stopped = true; }; - container.getDOMNode().dispatchEvent( event ); + fireEvent( node, event ); return interaction; } @@ -43,7 +43,7 @@ function fireKeyDown( container, keyCode, shiftKey ) { describe( 'NavigableMenu', () => { it( 'vertical: should navigate by up and down', () => { let currentIndex = 0; - const wrapper = mount( + const { container, getByRole } = render( /* Disabled because of our rule restricting literal IDs, preferring `withInstanceId`. In this case, it's fine to use literal IDs. @@ -71,17 +71,17 @@ describe( 'NavigableMenu', () => { /* eslint-enable no-restricted-syntax */ ); - simulateVisible( wrapper, '*' ); + simulateVisible( container, '*' ); - const container = wrapper.find( 'div' ); - wrapper - .getDOMNode() - .querySelector( '#btn1' ) - .focus(); + container.querySelector( '#btn1' ).focus(); // Navigate options function assertKeyDown( keyCode, expectedActiveIndex, expectedStop ) { - const interaction = fireKeyDown( container, keyCode, false ); + const interaction = fireKeyDown( + getByRole( 'menu' ), + keyCode, + false + ); expect( currentIndex ).toBe( expectedActiveIndex ); expect( interaction.stopped ).toBe( expectedStop ); } @@ -101,7 +101,7 @@ describe( 'NavigableMenu', () => { it( 'vertical: should navigate by up and down, and stop at edges', () => { let currentIndex = 0; - const wrapper = mount( + const { container, getByRole } = render( /* Disabled because of our rule restricting literal IDs, preferring `withInstanceId`. In this case, it's fine to use literal IDs. @@ -125,17 +125,17 @@ describe( 'NavigableMenu', () => { /* eslint-enable no-restricted-syntax */ ); - simulateVisible( wrapper, '*' ); + simulateVisible( container, '*' ); - const container = wrapper.find( 'div' ); - wrapper - .getDOMNode() - .querySelector( '#btn1' ) - .focus(); + container.querySelector( '#btn1' ).focus(); // Navigate options function assertKeyDown( keyCode, expectedActiveIndex, expectedStop ) { - const interaction = fireKeyDown( container, keyCode, false ); + const interaction = fireKeyDown( + getByRole( 'menu' ), + keyCode, + false + ); expect( currentIndex ).toBe( expectedActiveIndex ); expect( interaction.stopped ).toBe( expectedStop ); } @@ -153,7 +153,7 @@ describe( 'NavigableMenu', () => { it( 'horizontal: should navigate by left and right', () => { let currentIndex = 0; - const wrapper = mount( + const { container, getByRole } = render( /* Disabled because of our rule restricting literal IDs, preferring `withInstanceId`. In this case, it's fine to use literal IDs. @@ -181,17 +181,17 @@ describe( 'NavigableMenu', () => { /* eslint-enable no-restricted-syntax */ ); - simulateVisible( wrapper, '*' ); + simulateVisible( container, '*' ); - const container = wrapper.find( 'div' ); - wrapper - .getDOMNode() - .querySelector( '#btn1' ) - .focus(); + container.querySelector( '#btn1' ).focus(); // Navigate options function assertKeyDown( keyCode, expectedActiveIndex, expectedStop ) { - const interaction = fireKeyDown( container, keyCode, false ); + const interaction = fireKeyDown( + getByRole( 'menu' ), + keyCode, + false + ); expect( currentIndex ).toBe( expectedActiveIndex ); expect( interaction.stopped ).toBe( expectedStop ); } @@ -211,7 +211,7 @@ describe( 'NavigableMenu', () => { it( 'horizontal: should navigate by left and right, and stop at edges', () => { let currentIndex = 0; - const wrapper = mount( + const { container, getByRole } = render( /* Disabled because of our rule restricting literal IDs, preferring `withInstanceId`. In this case, it's fine to use literal IDs. @@ -235,17 +235,17 @@ describe( 'NavigableMenu', () => { /* eslint-enable no-restricted-syntax */ ); - simulateVisible( wrapper, '*' ); + simulateVisible( container, '*' ); - const container = wrapper.find( 'div' ); - wrapper - .getDOMNode() - .querySelector( '#btn1' ) - .focus(); + container.querySelector( '#btn1' ).focus(); // Navigate options function assertKeyDown( keyCode, expectedActiveIndex, expectedStop ) { - const interaction = fireKeyDown( container, keyCode, false ); + const interaction = fireKeyDown( + getByRole( 'menu' ), + keyCode, + false + ); expect( currentIndex ).toBe( expectedActiveIndex ); expect( interaction.stopped ).toBe( expectedStop ); } @@ -263,7 +263,7 @@ describe( 'NavigableMenu', () => { it( 'both: should navigate by up/down and left/right', () => { let currentIndex = 0; - const wrapper = mount( + const { container, getByRole } = render( /* Disabled because of our rule restricting literal IDs, preferring `withInstanceId`. In this case, it's fine to use literal IDs. @@ -280,17 +280,13 @@ describe( 'NavigableMenu', () => { /* eslint-enable no-restricted-syntax */ ); - simulateVisible( wrapper, '*' ); + simulateVisible( container, '*' ); - const container = wrapper.find( 'div' ); - wrapper - .getDOMNode() - .querySelector( '#btn1' ) - .focus(); + container.querySelector( '#btn1' ).focus(); // Navigate options function assertKeyDown( keyCode, expectedActiveIndex, expectedStop ) { - const interaction = fireKeyDown( container, keyCode ); + const interaction = fireKeyDown( getByRole( 'menu' ), keyCode ); expect( currentIndex ).toBe( expectedActiveIndex ); expect( interaction.stopped ).toBe( expectedStop ); } diff --git a/packages/components/src/navigable-container/test/tabbable.js b/packages/components/src/navigable-container/test/tabbable.js index 323cad39f4dc22..127a91ea9a847a 100644 --- a/packages/components/src/navigable-container/test/tabbable.js +++ b/packages/components/src/navigable-container/test/tabbable.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { mount } from 'enzyme'; +import { fireEvent, render } from '@testing-library/react'; import { each } from 'lodash'; /** @@ -14,8 +14,8 @@ import { TAB, SPACE } from '@wordpress/keycodes'; */ import { TabbableContainer } from '../tabbable'; -function simulateVisible( wrapper, selector ) { - const elements = wrapper.getDOMNode().querySelectorAll( selector ); +function simulateVisible( container, selector ) { + const elements = container.querySelectorAll( selector ); each( elements, ( elem ) => { elem.getClientRects = () => [ 'trick-jsdom-into-having-size-for-element-rect', @@ -23,7 +23,7 @@ function simulateVisible( wrapper, selector ) { } ); } -function fireKeyDown( container, keyCode, shiftKey ) { +function fireKeyDown( node, keyCode, shiftKey ) { const interaction = { stopped: false, }; @@ -35,7 +35,7 @@ function fireKeyDown( container, keyCode, shiftKey ) { event.stopImmediatePropagation = () => { interaction.stopped = true; }; - container.getDOMNode().dispatchEvent( event ); + fireEvent( node, event ); return interaction; } @@ -43,7 +43,7 @@ function fireKeyDown( container, keyCode, shiftKey ) { describe( 'TabbableContainer', () => { it( 'should navigate by keypresses', () => { let currentIndex = 0; - const wrapper = mount( + const { container } = render( /* Disabled because of our rule restricting literal IDs, preferring `withInstanceId`. In this case, it's fine to use literal IDs. @@ -71,13 +71,9 @@ describe( 'TabbableContainer', () => { /* eslint-enable no-restricted-syntax */ ); - simulateVisible( wrapper, '*' ); + simulateVisible( container, '*' ); - const container = wrapper.find( 'div.wrapper' ); - wrapper - .getDOMNode() - .querySelector( '#section1' ) - .focus(); + container.querySelector( '#section1' ).focus(); // Navigate options function assertKeyDown( @@ -86,7 +82,11 @@ describe( 'TabbableContainer', () => { expectedActiveIndex, expectedStop ) { - const interaction = fireKeyDown( container, keyCode, shiftKey ); + const interaction = fireKeyDown( + container.querySelector( '.wrapper' ), + keyCode, + shiftKey + ); expect( currentIndex ).toBe( expectedActiveIndex ); expect( interaction.stopped ).toBe( expectedStop ); } @@ -104,7 +104,7 @@ describe( 'TabbableContainer', () => { it( 'should navigate by keypresses and stop at edges', () => { let currentIndex = 0; - const wrapper = mount( + const { container } = render( /* Disabled because of our rule restricting literal IDs, preferring `withInstanceId`. In this case, it's fine to use literal IDs. @@ -128,13 +128,9 @@ describe( 'TabbableContainer', () => { /* eslint-enable no-restricted-syntax */ ); - simulateVisible( wrapper, '*' ); + simulateVisible( container, '*' ); - const container = wrapper.find( 'div.wrapper' ); - wrapper - .getDOMNode() - .querySelector( '#section1' ) - .focus(); + container.querySelector( '#section1' ).focus(); // Navigate options function assertKeyDown( @@ -143,7 +139,11 @@ describe( 'TabbableContainer', () => { expectedActiveIndex, expectedStop ) { - const interaction = fireKeyDown( container, keyCode, shiftKey ); + const interaction = fireKeyDown( + container.querySelector( '.wrapper' ), + keyCode, + shiftKey + ); expect( currentIndex ).toBe( expectedActiveIndex ); expect( interaction.stopped ).toBe( expectedStop ); } diff --git a/packages/components/src/notice/stories/index.js b/packages/components/src/notice/stories/index.js new file mode 100644 index 00000000000000..598bc420fbf950 --- /dev/null +++ b/packages/components/src/notice/stories/index.js @@ -0,0 +1,71 @@ +/** + * External dependencies + */ +import { boolean, select, text } from '@storybook/addon-knobs'; + +/** + * Internal dependencies + */ +import Notice from '../'; + +export default { + title: 'Components/Notice', + component: Notice, +}; + +export const _default = () => { + const status = select( + 'Status', + { + Warning: 'warning', + Success: 'success', + Error: 'error', + Info: 'info', + }, + 'info' + ); + const isDismissible = boolean( 'Is Dismissible', true ); + + return ( + <Notice status={ status } isDismissible={ isDismissible }> + <p>This is a notice.</p> + </Notice> + ); +}; + +export const withCustomSpokenMessage = () => { + const status = select( + 'Status', + { + Warning: 'warning', + Success: 'success', + Error: 'error', + Info: 'info', + }, + 'info' + ); + const isDismissible = boolean( 'Is Dismissible', true ); + const politeness = select( + 'Politeness', + { + Assertive: 'assertive', + Polite: 'polite', + }, + 'assertive' + ); + const spokenMessage = text( + 'Spoken Message', + 'This is a notice with a custom spoken message' + ); + + return ( + <Notice + status={ status } + isDismissible={ isDismissible } + politeness={ politeness } + spokenMessage={ spokenMessage } + > + <p>This is a notice.</p> + </Notice> + ); +}; diff --git a/packages/components/src/notice/style.scss b/packages/components/src/notice/style.scss index d69edcc61d8000..3ffb738ebbe07b 100644 --- a/packages/components/src/notice/style.scss +++ b/packages/components/src/notice/style.scss @@ -79,12 +79,5 @@ display: block; margin-left: 0; margin-top: $grid-unit-10; - - // Beyond mobile, align the action button on the right to use the space, and reduce margins so they don't add too much extra line-height. - @include break-medium() { - float: right; - margin-top: -$grid-unit-05; - margin-bottom: -$grid-unit-05; - } } } diff --git a/packages/components/src/number-control/README.md b/packages/components/src/number-control/README.md new file mode 100644 index 00000000000000..218ae241a63888 --- /dev/null +++ b/packages/components/src/number-control/README.md @@ -0,0 +1,29 @@ +# NumberControl + +NumberControl is an enhanced HTML [`input[type="number]`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/number) element. + +## Usage + +```jsx +import { __experimentalNumberControl as NumberControl } from '@wordpress/components'; + +const Example = () => { + const [value, setValue] = useState(10); + + return ( + <NumberControl + isShiftStepEnabled={ true } + onChange={ setValue } + shiftStep={ 10 } + value={ value } + /> + ) +}; +``` + +## Props + +Name | Type | Default | Description +--- | --- | --- | --- +`isShiftStepEnabled` | `boolean` | `true` | Determines if the unit `<select>` is tabbable. +`shiftStep` | `number` | `10` | Amount to increment by when the `shift` key is held down. \ No newline at end of file diff --git a/packages/components/src/number-control/index.js b/packages/components/src/number-control/index.js new file mode 100644 index 00000000000000..33914140975b06 --- /dev/null +++ b/packages/components/src/number-control/index.js @@ -0,0 +1,79 @@ +/** + * External dependencies + */ +import { clamp, noop } from 'lodash'; +import classNames from 'classnames'; + +/** + * WordPress dependencies + */ +import { UP, DOWN } from '@wordpress/keycodes'; + +export default function NumberControl( { + className, + isShiftStepEnabled = true, + max = Infinity, + min = -Infinity, + onChange = noop, + onKeyDown = noop, + shiftStep = 10, + step = 1, + ...props +} ) { + const baseValue = clamp( 0, min, max ); + + const handleOnKeyDown = ( event ) => { + onKeyDown( event ); + const { value } = event.target; + + const isEmpty = value === ''; + const enableShift = event.shiftKey && isShiftStepEnabled; + + const incrementalValue = enableShift + ? parseFloat( shiftStep ) + : parseFloat( step ); + let nextValue = isEmpty ? baseValue : value; + + // Convert to a number to use math + nextValue = parseFloat( nextValue ); + + switch ( event.keyCode ) { + case UP: + event.preventDefault(); + + nextValue = nextValue + incrementalValue; + nextValue = clamp( nextValue, min, max ); + + onChange( nextValue.toString(), { event } ); + + break; + + case DOWN: + event.preventDefault(); + + nextValue = nextValue - incrementalValue; + nextValue = clamp( nextValue, min, max ); + + onChange( nextValue.toString(), { event } ); + + break; + } + }; + + const handleOnChange = ( event ) => { + onChange( event.target.value, { event } ); + }; + + const classes = classNames( 'component-number-control', className ); + + return ( + <input + inputMode="numeric" + { ...props } + className={ classes } + type="number" + onChange={ handleOnChange } + onKeyDown={ handleOnKeyDown } + /> + ); +} diff --git a/packages/components/src/number-control/stories/index.js b/packages/components/src/number-control/stories/index.js new file mode 100644 index 00000000000000..b35af6a74eb11f --- /dev/null +++ b/packages/components/src/number-control/stories/index.js @@ -0,0 +1,35 @@ +/** + * External dependencies + */ +import { boolean, number } from '@storybook/addon-knobs'; + +/** + * WordPress dependencies + */ +import { useState } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import NumberControl from '../'; + +export default { + title: 'Components/NumberControl', + component: NumberControl, +}; + +function Example() { + const [ value, setValue ] = useState( '' ); + + const props = { + isShiftStepEnabled: boolean( 'isShiftStepEnabled', true ), + shiftStep: number( 'shiftStep', 10 ), + step: number( 'step', 1 ), + }; + + return <NumberControl { ...props } value={ value } onChange={ setValue } />; +} + +export const _default = () => { + return <Example />; +}; diff --git a/packages/components/src/number-control/test/index.js b/packages/components/src/number-control/test/index.js new file mode 100644 index 00000000000000..c946ba12aeb048 --- /dev/null +++ b/packages/components/src/number-control/test/index.js @@ -0,0 +1,303 @@ +/** + * External dependencies + */ +import { render, unmountComponentAtNode } from 'react-dom'; +import { act, Simulate } from 'react-dom/test-utils'; + +/** + * WordPress dependencies + */ +import { useState } from '@wordpress/element'; +import { UP, DOWN } from '@wordpress/keycodes'; + +/** + * Internal dependencies + */ +import NumberControl from '../'; + +let container = null; + +function getInput() { + return container.querySelector( 'input' ); +} + +beforeEach( () => { + container = document.createElement( 'div' ); + document.body.appendChild( container ); +} ); + +afterEach( () => { + unmountComponentAtNode( container ); + container.remove(); + container = null; +} ); + +function StatefulNumberControl( props ) { + const [ value, setValue ] = useState( props.value ); + const handleOnChange = ( v ) => setValue( v ); + + return ( + <NumberControl + { ...props } + value={ value } + onChange={ handleOnChange } + /> + ); +} + +describe( 'NumberControl', () => { + describe( 'Basic rendering', () => { + it( 'should render', () => { + act( () => { + render( <NumberControl />, container ); + } ); + + const input = getInput(); + + expect( input ).not.toBeNull(); + } ); + + it( 'should render custom className', () => { + act( () => { + render( <NumberControl className="hello" />, container ); + } ); + + const input = getInput(); + + expect( input.classList.contains( 'hello' ) ).toBe( true ); + } ); + } ); + + describe( 'onChange handling', () => { + it( 'should provide onChange callback with string value', () => { + const spy = jest.fn(); + act( () => { + render( + <NumberControl value={ 5 } onChange={ spy } />, + container + ); + } ); + + const input = getInput(); + + input.value = 10; + Simulate.change( input ); + + expect( spy.mock.calls[ 0 ][ 0 ] ).toBe( '10' ); + } ); + } ); + + describe( 'Key UP interactions', () => { + it( 'should fire onKeyDown callback', () => { + const spy = jest.fn(); + act( () => { + render( + <StatefulNumberControl value={ 5 } onKeyDown={ spy } />, + container + ); + } ); + + const input = getInput(); + + Simulate.keyDown( input, { keyCode: UP } ); + + expect( spy ).toHaveBeenCalled(); + } ); + + it( 'should increment by step on key UP press', () => { + act( () => { + render( <StatefulNumberControl value={ 5 } />, container ); + } ); + + const input = getInput(); + + Simulate.keyDown( input, { keyCode: UP } ); + + expect( input.value ).toBe( '6' ); + } ); + + it( 'should increment from a negative value', () => { + act( () => { + render( <StatefulNumberControl value={ -5 } />, container ); + } ); + + const input = getInput(); + + Simulate.keyDown( input, { keyCode: UP } ); + + expect( input.value ).toBe( '-4' ); + } ); + + it( 'should increment by shiftStep on key UP + shift press', () => { + act( () => { + render( <StatefulNumberControl value={ 5 } />, container ); + } ); + + const input = getInput(); + + Simulate.keyDown( input, { keyCode: UP, shiftKey: true } ); + + expect( input.value ).toBe( '15' ); + } ); + + it( 'should increment by custom shiftStep on key UP + shift press', () => { + act( () => { + render( + <StatefulNumberControl value={ 5 } shiftStep={ 100 } />, + container + ); + } ); + + const input = getInput(); + + Simulate.keyDown( input, { keyCode: UP, shiftKey: true } ); + + expect( input.value ).toBe( '105' ); + } ); + + it( 'should increment but be limited by max on shiftStep', () => { + act( () => { + render( + <StatefulNumberControl + value={ 5 } + shiftStep={ 100 } + max={ 99 } + />, + container + ); + } ); + + const input = getInput(); + + Simulate.keyDown( input, { keyCode: UP, shiftKey: true } ); + + expect( input.value ).toBe( '99' ); + } ); + + it( 'should not increment by shiftStep if disabled', () => { + act( () => { + render( + <StatefulNumberControl + value={ 5 } + shiftStep={ 100 } + isShiftStepEnabled={ false } + />, + container + ); + } ); + + const input = getInput(); + + Simulate.keyDown( input, { keyCode: UP, shiftKey: true } ); + + expect( input.value ).toBe( '6' ); + } ); + } ); + + describe( 'Key DOWN interactions', () => { + it( 'should fire onKeyDown callback', () => { + const spy = jest.fn(); + act( () => { + render( + <StatefulNumberControl value={ 5 } onKeyDown={ spy } />, + container + ); + } ); + + const input = getInput(); + + Simulate.keyDown( input, { keyCode: DOWN } ); + + expect( spy ).toHaveBeenCalled(); + } ); + + it( 'should decrement by step on key DOWN press', () => { + act( () => { + render( <StatefulNumberControl value={ 5 } />, container ); + } ); + + const input = getInput(); + + Simulate.keyDown( input, { keyCode: DOWN } ); + + expect( input.value ).toBe( '4' ); + } ); + + it( 'should decrement from a negative value', () => { + act( () => { + render( <StatefulNumberControl value={ -5 } />, container ); + } ); + + const input = getInput(); + + Simulate.keyDown( input, { keyCode: DOWN } ); + + expect( input.value ).toBe( '-6' ); + } ); + + it( 'should decrement by shiftStep on key DOWN + shift press', () => { + act( () => { + render( <StatefulNumberControl value={ 5 } />, container ); + } ); + + const input = getInput(); + + Simulate.keyDown( input, { keyCode: DOWN, shiftKey: true } ); + + expect( input.value ).toBe( '-5' ); + } ); + + it( 'should decrement by custom shiftStep on key DOWN + shift press', () => { + act( () => { + render( + <StatefulNumberControl value={ 5 } shiftStep={ 100 } />, + container + ); + } ); + + const input = getInput(); + + Simulate.keyDown( input, { keyCode: DOWN, shiftKey: true } ); + + expect( input.value ).toBe( '-95' ); + } ); + + it( 'should decrement but be limited by min on shiftStep', () => { + act( () => { + render( + <StatefulNumberControl + value={ 5 } + shiftStep={ 100 } + min={ 4 } + />, + container + ); + } ); + + const input = getInput(); + + Simulate.keyDown( input, { keyCode: DOWN, shiftKey: true } ); + + expect( input.value ).toBe( '4' ); + } ); + + it( 'should not decrement by shiftStep if disabled', () => { + act( () => { + render( + <StatefulNumberControl + value={ 5 } + shiftStep={ 100 } + isShiftStepEnabled={ false } + />, + container + ); + } ); + + const input = getInput(); + + Simulate.keyDown( input, { keyCode: DOWN, shiftKey: true } ); + + expect( input.value ).toBe( '4' ); + } ); + } ); +} ); diff --git a/packages/components/src/panel/body.native.js b/packages/components/src/panel/body.native.js index 87c5eeb60bac7f..36126ea76a9f5b 100644 --- a/packages/components/src/panel/body.native.js +++ b/packages/components/src/panel/body.native.js @@ -19,10 +19,10 @@ export class PanelBody extends Component { } render() { - const { children, title } = this.props; + const { children, title, style = {} } = this.props; return ( - <View style={ styles.panelContainer }> + <View style={ [ styles.panelContainer, style ] }> { title && ( <Text style={ styles.sectionHeaderText }>{ title }</Text> ) } diff --git a/packages/components/src/panel/style.scss b/packages/components/src/panel/style.scss index 944186713453d9..fa53a3ceb130f4 100644 --- a/packages/components/src/panel/style.scss +++ b/packages/components/src/panel/style.scss @@ -70,8 +70,8 @@ // Hover States .components-panel__body > .components-panel__body-title:hover { // Override the default button hover style - background: $light-gray-200 !important; - border: none !important; + background: $light-gray-200; + border: none; } .components-panel__body-toggle.components-button { @@ -82,20 +82,15 @@ font-weight: 600; text-align: left; color: $dark-gray-900; - @include menu-style__neutral; + border: none; + box-shadow: none; transition: 0.1s background ease-in-out; @include reduce-motion("transition"); height: auto; - &:focus:not(:disabled):not([aria-disabled="true"]) { - @include menu-style__focus; - } - - &:hover { - // Override the default button hover style - background: transparent !important; - border: none !important; - box-shadow: none !important; + &:focus { + box-shadow: inset 0 0 0 $border-width-focus $theme-color; + border-radius: 0; } .components-panel__arrow { diff --git a/packages/components/src/placeholder/style.scss b/packages/components/src/placeholder/style.scss index 04efa290269387..2feaa22804b09b 100644 --- a/packages/components/src/placeholder/style.scss +++ b/packages/components/src/placeholder/style.scss @@ -22,7 +22,7 @@ // Block UI appearance. border-radius: $radius-block-ui; background-color: $white; - box-shadow: 0 0 0 $border-width $dark-gray-primary; + box-shadow: inset 0 0 0 $border-width $dark-gray-primary; outline: 1px solid transparent; // Shown for Windows 10 High Contrast mode. .components-base-control__label { diff --git a/packages/components/src/popover/README.md b/packages/components/src/popover/README.md index be0eca3d773580..6dc54e4e1f53cb 100644 --- a/packages/components/src/popover/README.md +++ b/packages/components/src/popover/README.md @@ -127,11 +127,22 @@ Opt-in prop to show popovers fullscreen on mobile, pass `false` in this prop to ### anchorRect -A custom `DOMRect` object at which to position the popover. +A custom `DOMRect` object at which to position the popover. `anchorRect` is used when the position (custom `DOMRect` object) of the popover needs to be fixed at one location all the time. - Type: `DOMRect` - Required: No +### getAnchorRect + +A callback function which is used to override the anchor value computation algorithm. `anchorRect` will take precedence over this prop, if both are passed together. + +If you need the `DOMRect` object i.e., the position of popover to be calculated on every time, the popover re-renders, then use `getAnchorRect`. + +`getAnchorRect` callback function receives a reference to the popover anchor element as a function parameter and it should return a `DOMRect` objcet. + +- Type: `Function` +- Required: No + ## Methods ### refresh diff --git a/packages/components/src/popover/index.js b/packages/components/src/popover/index.js index 2e06f907de8a75..13aa4b34dfe669 100644 --- a/packages/components/src/popover/index.js +++ b/packages/components/src/popover/index.js @@ -233,10 +233,11 @@ const Popover = ( { children, className, noArrow = true, + isAlternate, // Disable reason: We generate the `...contentProps` rest as remainder // of props which aren't explicitly handled by this component. /* eslint-disable no-unused-vars */ - position = 'top', + position = 'bottom right', range, focusOnMount = 'firstElement', anchorRef, @@ -270,6 +271,7 @@ const Popover = ( { useEffect( () => { if ( isExpanded ) { setClass( containerRef.current, 'is-without-arrow', noArrow ); + setClass( containerRef.current, 'is-alternate', isAlternate ); setAttribute( containerRef.current, 'data-x-axis' ); setAttribute( containerRef.current, 'data-y-axis' ); setStyle( containerRef.current, 'top' ); @@ -392,6 +394,7 @@ const Popover = ( { 'is-without-arrow', noArrow || ( xAxis === 'center' && yAxis === 'middle' ) ); + setClass( containerRef.current, 'is-alternate', isAlternate ); setAttribute( containerRef.current, 'data-x-axis', xAxis ); setAttribute( containerRef.current, 'data-y-axis', yAxis ); setStyle( @@ -575,6 +578,7 @@ const Popover = ( { { 'is-expanded': isExpanded, 'is-without-arrow': noArrow, + 'is-alternate': isAlternate, } ) } { ...contentProps } diff --git a/packages/components/src/popover/style.scss b/packages/components/src/popover/style.scss index 7ece47bcdb9d79..74a57d17197d29 100644 --- a/packages/components/src/popover/style.scss +++ b/packages/components/src/popover/style.scss @@ -140,6 +140,23 @@ $arrow-size: 8px; align-items: center; display: flex; } + + // Add spacing. + &.is-from-top { + margin-top: $grid-unit-15; + } + + &.is-from-bottom { + margin-top: -$grid-unit-15; + } + + &.is-from-left:not(.is-from-top):not(.is-from-bottom) { + margin-left: $grid-unit-15; + } + + &.is-from-right:not(.is-from-top):not(.is-from-bottom) { + margin-right: $grid-unit-15; + } } .components-popover__content { @@ -149,6 +166,12 @@ $arrow-size: 8px; box-shadow: $shadow-popover; border-radius: $radius-block-ui; + // Alternate treatment for popovers that put them at elevation zero with high contrast. + .is-alternate & { + border: $border-width solid $dark-gray-primary; + box-shadow: none; + } + .components-popover & { position: absolute; height: auto; diff --git a/packages/components/src/popover/test/index.js b/packages/components/src/popover/test/index.js index 8db3d9292cee3d..d46c54cd03a94f 100644 --- a/packages/components/src/popover/test/index.js +++ b/packages/components/src/popover/test/index.js @@ -1,26 +1,13 @@ /** * External dependencies */ -import TestUtils from 'react-dom/test-utils'; - -/** - * WordPress dependencies - */ -import { Component } from '@wordpress/element'; +import { act, render } from '@testing-library/react'; /** * Internal dependencies */ import Popover from '../'; -jest.useFakeTimers(); - -class PopoverWrapper extends Component { - render() { - return <Popover { ...this.props } />; - } -} - describe( 'Popover', () => { afterEach( () => { if ( document.activeElement ) { @@ -34,61 +21,50 @@ describe( 'Popover', () => { document.dispatchEvent( new window.KeyboardEvent( 'keydown' ) ); document.dispatchEvent( new window.KeyboardEvent( 'keyup' ) ); + expect( document.activeElement ).toBe( document.body ); + // An ideal test here would mount with an input child and focus the // child, but in context of JSDOM the inputs are not visible and // are therefore skipped as tabbable, defaulting to popover. - let wrapper; - TestUtils.act( () => { - wrapper = TestUtils.renderIntoDocument( <PopoverWrapper /> ); + let result; + act( () => { + result = render( <Popover /> ); jest.advanceTimersByTime( 1 ); - - const content = TestUtils.findRenderedDOMComponentWithClass( - wrapper, - 'components-popover__content' - ); - expect( document.activeElement ).toBe( content ); } ); + + expect( document.activeElement ).toBe( + result.container.querySelector( '.components-popover__content' ) + ); } ); it( 'should allow focus-on-open behavior to be disabled', () => { - const activeElement = document.activeElement; - TestUtils.act( () => { - TestUtils.renderIntoDocument( <Popover focusOnMount={ false } /> ); + expect( document.activeElement ).toBe( document.body ); - jest.advanceTimersByTime( 1 ); + act( () => { + render( <Popover focusOnMount={ false } /> ); - expect( document.activeElement ).toBe( activeElement ); + jest.advanceTimersByTime( 1 ); } ); + + expect( document.activeElement ).toBe( document.body ); } ); it( 'should render content', () => { - let wrapper; - TestUtils.act( () => { - wrapper = TestUtils.renderIntoDocument( - <PopoverWrapper>Hello</PopoverWrapper> - ); + let result; + act( () => { + result = render( <Popover>Hello</Popover> ); } ); - const content = TestUtils.findRenderedDOMComponentWithTag( - wrapper, - 'span' - ); - expect( content ).toMatchSnapshot(); + expect( result.container.querySelector( 'span' ) ).toMatchSnapshot(); } ); it( 'should pass additional props to portaled element', () => { - let wrapper; - TestUtils.act( () => { - wrapper = TestUtils.renderIntoDocument( - <PopoverWrapper role="tooltip">Hello</PopoverWrapper> - ); + let result; + act( () => { + result = render( <Popover role="tooltip">Hello</Popover> ); } ); - const content = TestUtils.findRenderedDOMComponentWithTag( - wrapper, - 'span' - ); - expect( content ).toMatchSnapshot(); + expect( result.container.querySelector( 'span' ) ).toMatchSnapshot(); } ); } ); diff --git a/packages/components/src/query-controls/index.js b/packages/components/src/query-controls/index.js index 67c975b8e4bee8..a1a1a2bc4a4cf9 100644 --- a/packages/components/src/query-controls/index.js +++ b/packages/components/src/query-controls/index.js @@ -2,7 +2,6 @@ * WordPress dependencies */ import { __ } from '@wordpress/i18n'; -import { Platform } from '@wordpress/element'; /** * Internal dependencies @@ -13,17 +12,6 @@ const DEFAULT_MIN_ITEMS = 1; const DEFAULT_MAX_ITEMS = 100; const MAX_CATEGORIES_SUGGESTIONS = 20; -// currently this is needed for consistent controls UI on mobile -// this can be removed after control components settle on consistent defaults -const MOBILE_CONTROL_PROPS = Platform.select( { - web: {}, - native: { separatorType: 'fullWidth' }, -} ); -const MOBILE_CONTROL_PROPS_SEPARATOR_NONE = Platform.select( { - web: {}, - native: { separatorType: 'none' }, -} ); - export default function QueryControls( { categorySuggestions, selectedCategories, @@ -72,7 +60,6 @@ export default function QueryControls( { onOrderByChange( newOrderBy ); } } } - { ...MOBILE_CONTROL_PROPS } /> ), onCategoryChange && ( @@ -100,7 +87,6 @@ export default function QueryControls( { min={ minItems } max={ maxItems } required - { ...MOBILE_CONTROL_PROPS_SEPARATOR_NONE } /> ), ]; diff --git a/packages/components/src/query-controls/index.native.js b/packages/components/src/query-controls/index.native.js new file mode 100644 index 00000000000000..e7932cd2854991 --- /dev/null +++ b/packages/components/src/query-controls/index.native.js @@ -0,0 +1,87 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import { RangeControl, SelectControl } from '../'; +import CategorySelect from './category-select'; + +const DEFAULT_MIN_ITEMS = 1; +const DEFAULT_MAX_ITEMS = 100; + +export default function QueryControls( { + categoriesList, + selectedCategoryId, + numberOfItems, + order, + orderBy, + maxItems = DEFAULT_MAX_ITEMS, + minItems = DEFAULT_MIN_ITEMS, + onCategoryChange, + onNumberOfItemsChange, + onOrderChange, + onOrderByChange, +} ) { + return [ + onOrderChange && onOrderByChange && ( + <SelectControl + label={ __( 'Order by' ) } + value={ `${ orderBy }/${ order }` } + options={ [ + { + label: __( 'Newest to oldest' ), + value: 'date/desc', + }, + { + label: __( 'Oldest to newest' ), + value: 'date/asc', + }, + { + /* translators: label for ordering posts by title in ascending order */ + label: __( 'A β†’ Z' ), + value: 'title/asc', + }, + { + /* translators: label for ordering posts by title in descending order */ + label: __( 'Z β†’ A' ), + value: 'title/desc', + }, + ] } + onChange={ ( value ) => { + const [ newOrderBy, newOrder ] = value.split( '/' ); + if ( newOrder !== order ) { + onOrderChange( newOrder ); + } + if ( newOrderBy !== orderBy ) { + onOrderByChange( newOrderBy ); + } + } } + { ...{ separatorType: 'fullWidth' } } + /> + ), + onCategoryChange && ( + <CategorySelect + categoriesList={ categoriesList } + label={ __( 'Category' ) } + noOptionLabel={ __( 'All' ) } + selectedCategoryId={ selectedCategoryId } + onChange={ onCategoryChange } + { ...{ separatorType: 'fullWidth' } } + /> + ), + onNumberOfItemsChange && ( + <RangeControl + label={ __( 'Number of items' ) } + value={ numberOfItems } + onChange={ onNumberOfItemsChange } + min={ minItems } + max={ maxItems } + required + { ...{ separatorType: 'none' } } + /> + ), + ]; +} diff --git a/packages/components/src/radio-context/index.js b/packages/components/src/radio-context/index.js new file mode 100644 index 00000000000000..58a7783dcb84e0 --- /dev/null +++ b/packages/components/src/radio-context/index.js @@ -0,0 +1,11 @@ +/** + * WordPress dependencies + */ +import { createContext } from '@wordpress/element'; + +const RadioContext = createContext( { + state: null, + setState: () => {}, +} ); + +export default RadioContext; diff --git a/packages/components/src/radio-control/README.md b/packages/components/src/radio-control/README.md index 2a55a81718fb15..f08f7da87b4953 100644 --- a/packages/components/src/radio-control/README.md +++ b/packages/components/src/radio-control/README.md @@ -121,3 +121,4 @@ A function that receives the value of the new option that is being selected as i * To select one or more items from a set, use the `CheckboxControl` component. * To toggle a single setting on or off, use the `ToggleControl` component. +* To format as a button group, use the `RadioGroup` component. diff --git a/packages/components/src/radio-group/README.md b/packages/components/src/radio-group/README.md new file mode 100644 index 00000000000000..7c6eab29b0bf1e --- /dev/null +++ b/packages/components/src/radio-group/README.md @@ -0,0 +1,87 @@ +# RadioGroup + +Use a RadioGroup component when you want users to select one option from a small set of options. + +![RadioGroup component](https://wordpress.org/gutenberg/files/2018/12/s_96EC471FE9C9D91A996770229947AAB54A03351BDE98F444FD3C1BF0CED365EA_1541792995815_ButtonGroup.png) + +## Table of contents + +1. [Design guidelines](#design-guidelines) +2. [Development guidelines](#development-guidelines) +3. [Related components](#related-components) + +## Design guidelines + +### Usage + +#### Selected action + +Only one option in a radio group can be selected and active at a time. Selecting one option deselects any other. + +### Best practices + +Radio groups should: + +- **Be clearly and accurately labeled.** +- **Clearly communicate that clicking or tapping will trigger an action.** +- **Use established colors appropriately.** For example, only use red buttons for actions that are difficult or impossible to undo. +- **Have consistent locations in the interface.** +- **Have a default option already selected.** + +### States + +#### Active and available radio groups + +A radio group’s state makes it clear which option is active. Hover and focus states express the available selection options for buttons in a button group. + +#### Disabled radio groups + +Radio groups that cannot be selected can either be given a disabled state, or be hidden. + +## Development guidelines + +### Usage + +#### Controlled + +```jsx +import { Radio, RadioGroup } from '@wordpress/components'; +import { useState } from '@wordpress/element'; + +const MyControlledRadioRadioGroup = () => { + const [ checked, setChecked ] = useState( '25' ); + return ( + <RadioGroup accessibilityLabel="Width" onChange={ setChecked } checked={ checked }> + <Radio value="25">25%</Radio> + <Radio value="50">50%</Radio> + <Radio value="75">75%</Radio> + <Radio value="100">100%</Radio> + </RadioGroup> + ); +}; +``` + +#### Uncontrolled + +When using the RadioGroup component as an uncontrolled component, the default value can be set with the `defaultChecked` prop. + +```jsx +import { Radio, RadioGroup } from '@wordpress/components'; +import { useState } from '@wordpress/element'; + +const MyUncontrolledRadioRadioGroup = () => { + return ( + <RadioGroup accessibilityLabel="Width" defaultChecked="25"> + <Radio value="25">25%</Radio> + <Radio value="50">50%</Radio> + <Radio value="75">75%</Radio> + <Radio value="100">100%</Radio> + </RadioGroup> + ); +}; +``` + +## Related components + +- For simple buttons that are related, use a `ButtonGroup` component. +- For traditional radio options, use a `RadioControl` component. diff --git a/packages/components/src/radio-group/index.js b/packages/components/src/radio-group/index.js new file mode 100644 index 00000000000000..11f24605297923 --- /dev/null +++ b/packages/components/src/radio-group/index.js @@ -0,0 +1,53 @@ +/** + * External dependencies + */ +import { useRadioState, RadioGroup as ReakitRadioGroup } from 'reakit/Radio'; + +/** + * WordPress dependencies + */ +import { forwardRef } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import ButtonGroup from '../button-group'; +import RadioContext from '../radio-context'; + +function RadioGroup( + { + accessibilityLabel, + checked, + defaultChecked, + disabled, + onChange, + ...props + }, + ref +) { + const radioState = useRadioState( { + state: defaultChecked, + baseId: props.id, + } ); + const radioContext = { + ...radioState, + disabled, + // controlled or uncontrolled + state: checked || radioState.state, + setState: onChange || radioState.setState, + }; + + return ( + <RadioContext.Provider value={ radioContext }> + <ReakitRadioGroup + ref={ ref } + as={ ButtonGroup } + aria-label={ accessibilityLabel } + { ...radioState } + { ...props } + /> + </RadioContext.Provider> + ); +} + +export default forwardRef( RadioGroup ); diff --git a/packages/components/src/radio-group/stories/index.js b/packages/components/src/radio-group/stories/index.js new file mode 100644 index 00000000000000..5844cd82016b57 --- /dev/null +++ b/packages/components/src/radio-group/stories/index.js @@ -0,0 +1,71 @@ +/** + * WordPress dependencies + */ +import { useState } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import Radio from '../../radio'; +import RadioGroup from '../'; + +export default { title: 'Components/RadioGroup', component: RadioGroup }; + +export const _default = () => { + /* eslint-disable no-restricted-syntax */ + return ( + <RadioGroup + // id is required for server side rendering + id="default-radiogroup" + accessibilityLabel="options" + defaultChecked="option2" + > + <Radio value="option1">Option 1</Radio> + <Radio value="option2">Option 2</Radio> + <Radio value="option3">Option 3</Radio> + </RadioGroup> + ); + /* eslint-enable no-restricted-syntax */ +}; + +export const disabled = () => { + /* eslint-disable no-restricted-syntax */ + return ( + <RadioGroup + // id is required for server side rendering + id="disabled-radiogroup" + disabled + accessibilityLabel="options" + defaultChecked="option2" + > + <Radio value="option1">Option 1</Radio> + <Radio value="option2">Option 2</Radio> + <Radio value="option3">Option 3</Radio> + </RadioGroup> + ); + /* eslint-enable no-restricted-syntax */ +}; + +const ControlledRadioGroupWithState = () => { + const [ checked, setChecked ] = useState( 'option2' ); + + /* eslint-disable no-restricted-syntax */ + return ( + <RadioGroup + // id is required for server side rendering + id="controlled-radiogroup" + accessibilityLabel="options" + checked={ checked } + onChange={ setChecked } + > + <Radio value="option1">Option 1</Radio> + <Radio value="option2">Option 2</Radio> + <Radio value="option3">Option 3</Radio> + </RadioGroup> + ); + /* eslint-enable no-restricted-syntax */ +}; + +export const controlled = () => { + return <ControlledRadioGroupWithState />; +}; diff --git a/packages/components/src/radio/index.js b/packages/components/src/radio/index.js new file mode 100644 index 00000000000000..6d7305002e3fce --- /dev/null +++ b/packages/components/src/radio/index.js @@ -0,0 +1,36 @@ +/** + * External dependencies + */ +import { Radio as ReakitRadio } from 'reakit/Radio'; + +/** + * WordPress dependencies + */ +import { useContext, forwardRef } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import Button from '../button'; +import RadioContext from '../radio-context'; + +function Radio( { children, value, ...props }, ref ) { + const radioContext = useContext( RadioContext ); + const checked = radioContext.state === value; + + return ( + <ReakitRadio + ref={ ref } + as={ Button } + isPrimary={ checked } + isSecondary={ ! checked } + value={ value } + { ...radioContext } + { ...props } + > + { children || value } + </ReakitRadio> + ); +} + +export default forwardRef( Radio ); diff --git a/packages/components/src/radio/stories/index.js b/packages/components/src/radio/stories/index.js new file mode 100644 index 00000000000000..b64c35ed7ba17f --- /dev/null +++ b/packages/components/src/radio/stories/index.js @@ -0,0 +1,20 @@ +/** + * Internal dependencies + */ +import RadioGroup from '../../radio-group'; +import Radio from '../'; + +export default { title: 'Components/Radio', component: Radio }; + +export const _default = () => { + // Radio components must be a descendent of a RadioGroup component. + /* eslint-disable no-restricted-syntax */ + return ( + // id is required for server side rendering + <RadioGroup id="default-radiogroup" accessibilityLabel="options"> + <Radio value="option1">Option 1</Radio> + <Radio value="option2">Option 2</Radio> + </RadioGroup> + ); + /* eslint-enable no-restricted-syntax */ +}; diff --git a/packages/components/src/range-control/README.md b/packages/components/src/range-control/README.md index ea1bd196d53eb0..a014b31d6ede9e 100644 --- a/packages/components/src/range-control/README.md +++ b/packages/components/src/range-control/README.md @@ -294,6 +294,14 @@ Define if separator line under/above control row should be disabled or full widt - Required: No - Platform: Mobile +#### type + +Define if the value selection should present a stepper control or a slider control in the bottom sheet on mobile. To use the stepper set the type value as `stepper`. Defaults to slider if no option is provided. + +- Type: `String` +- Required: No +- Platform: Mobile + ## Related components - To collect a numerical input in a text field, use the `TextControl` component. diff --git a/packages/components/src/range-control/index.js b/packages/components/src/range-control/index.js index cee2659ed04e85..d718dec1a229a0 100644 --- a/packages/components/src/range-control/index.js +++ b/packages/components/src/range-control/index.js @@ -64,7 +64,7 @@ const BaseRangeControl = forwardRef( renderTooltipContent = ( v ) => v, showTooltip: showTooltipProp, step = 1, - value: valueProp = 0, + value: valueProp, withInputField = true, ...props }, @@ -72,7 +72,9 @@ const BaseRangeControl = forwardRef( ) => { const isRTL = useRtl(); - const sliderValue = valueProp || initialPosition; + const sliderValue = + valueProp !== undefined ? valueProp : initialPosition; + const [ value, setValue ] = useControlledRangeValue( { min, max, @@ -95,8 +97,9 @@ const BaseRangeControl = forwardRef( const isThumbFocused = ! disabled && isFocused; const isValueReset = value === null; - const inputSliderValue = isValueReset ? '' : value; - const currentInputValue = isValueReset ? '' : value || currentInput; + const currentValue = value !== undefined ? value : currentInput; + + const inputSliderValue = isValueReset ? '' : currentValue; const rangeFillValue = isValueReset ? floatClamp( max / 2, min, max ) @@ -119,12 +122,20 @@ const BaseRangeControl = forwardRef( const enableTooltip = showTooltipProp !== false && isFinite( value ); const handleOnChange = ( event ) => { - if ( ! event.target.checkValidity() ) { + if ( + event.target.checkValidity && + ! event.target.checkValidity() + ) { return; } const nextValue = parseFloat( event.target.value ); + if ( isNaN( nextValue ) ) { + handleOnReset(); + return; + } + setValue( nextValue ); onChange( nextValue ); }; @@ -249,7 +260,7 @@ const BaseRangeControl = forwardRef( onChange={ handleOnChange } step={ step } type="number" - value={ currentInputValue } + value={ inputSliderValue } /> ) } { allowReset && ( diff --git a/packages/components/src/range-control/index.native.js b/packages/components/src/range-control/index.native.js index 5fe4a9f733e0d6..88ec3f870b1b0d 100644 --- a/packages/components/src/range-control/index.native.js +++ b/packages/components/src/range-control/index.native.js @@ -2,6 +2,7 @@ * Internal dependencies */ import RangeCell from '../mobile/bottom-sheet/range-cell'; +import StepperCell from '../mobile/bottom-sheet/stepper-cell'; function RangeControl( { className, @@ -17,12 +18,24 @@ function RangeControl( { initialPosition, min, max, + type, + separatorType, ...props } ) { + if ( type === 'stepper' ) { + return ( + <StepperCell + label={ label } + max={ max } + min={ min } + onChange={ onChange } + separatorType={ separatorType } + value={ value } + /> + ); + } const id = `inspector-range-control-${ instanceId }`; - const currentInputValue = currentInput === null ? value : currentInput; - const initialSliderValue = isFinite( currentInputValue ) ? currentInputValue : initialPosition; diff --git a/packages/components/src/range-control/rail.js b/packages/components/src/range-control/rail.js index d0bedcf7ac82b6..111cf8d96972d7 100644 --- a/packages/components/src/range-control/rail.js +++ b/packages/components/src/range-control/rail.js @@ -1,7 +1,3 @@ -/** - * External dependencies - */ -import { isUndefined } from 'lodash'; /** * Internal dependencies */ @@ -78,7 +74,7 @@ function useMarks( { marks, min = 0, max = 100, step = 1, value = 0 } ) { } ) ); const enhancedMarks = marksArray.map( ( mark, index ) => { - const markValue = ! isUndefined( mark.value ) ? mark.value : value; + const markValue = mark.value !== undefined ? mark.value : value; const key = `mark-${ index }`; const isFilled = markValue * step <= value; diff --git a/packages/components/src/range-control/test/index.js b/packages/components/src/range-control/test/index.js index 4c67a4f9c1a8f6..31c72383a0271e 100644 --- a/packages/components/src/range-control/test/index.js +++ b/packages/components/src/range-control/test/index.js @@ -1,7 +1,8 @@ /** * External dependencies */ -import TestUtils, { act } from 'react-dom/test-utils'; +import { render, unmountComponentAtNode } from 'react-dom'; +import TestUtils, { act, Simulate } from 'react-dom/test-utils'; /** * Internal dependencies @@ -14,6 +15,19 @@ import RangeControl from '../'; import { Component } from '@wordpress/element'; import { Dashicon } from '@wordpress/components'; +let container = null; + +beforeEach( () => { + container = document.createElement( 'div' ); + document.body.appendChild( container ); +} ); + +afterEach( () => { + unmountComponentAtNode( container ); + container.remove(); + container = null; +} ); + describe( 'RangeControl', () => { class TestWrapper extends Component { render() { @@ -326,6 +340,79 @@ describe( 'RangeControl', () => { } ); } ); + describe( 'input field', () => { + it( 'should render an input field by default', () => { + act( () => { + render( <RangeControl />, container ); + } ); + const field = container.querySelector( 'input[type="number"]' ); + + expect( field ).toBeTruthy(); + } ); + + it( 'should not render an input field, if disabled', () => { + act( () => { + render( <RangeControl withInputField={ false } />, container ); + } ); + const field = container.querySelector( 'input[type="number"]' ); + + expect( field ).toBeFalsy(); + } ); + + it( 'should render a zero value into input range and field', () => { + act( () => { + render( <RangeControl value={ 0 } />, container ); + } ); + const range = container.querySelector( 'input[type="range"]' ); + const field = container.querySelector( 'input[type="number"]' ); + + expect( range.value ).toBe( '0' ); + expect( field.value ).toBe( '0' ); + } ); + + it( 'should update both field and range on change', () => { + act( () => { + render( <RangeControl value={ 0 } />, container ); + } ); + const range = container.querySelector( 'input[type="range"]' ); + const field = container.querySelector( 'input[type="number"]' ); + + act( () => { + Simulate.change( range, { target: { value: 13 } } ); + } ); + + expect( range.value ).toBe( '13' ); + expect( field.value ).toBe( '13' ); + + act( () => { + Simulate.change( field, { target: { value: 7 } } ); + } ); + + expect( range.value ).toBe( '7' ); + expect( field.value ).toBe( '7' ); + } ); + + it( 'should reset input values if next value is removed', () => { + act( () => { + render( <RangeControl value={ 13 } />, container ); + } ); + const range = container.querySelector( 'input[type="range"]' ); + const field = container.querySelector( 'input[type="number"]' ); + + expect( range.value ).toBe( '13' ); + expect( field.value ).toBe( '13' ); + + act( () => { + Simulate.change( field, { target: { value: undefined } } ); + } ); + + // Reset to 50. Median value of min: 0, max: 100 + expect( range.value ).toBe( '50' ); + // Input field should be blank + expect( field.value ).toBe( '' ); + } ); + } ); + describe( 'reset', () => { class StatefulTestWrapper extends Component { constructor( props ) { diff --git a/packages/components/src/range-control/utils.js b/packages/components/src/range-control/utils.js index d1fd148ec2a3fb..9d2aecfa5e7a70 100644 --- a/packages/components/src/range-control/utils.js +++ b/packages/components/src/range-control/utils.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { clamp, isFinite, noop } from 'lodash'; +import { clamp, noop } from 'lodash'; /** * WordPress dependencies diff --git a/packages/components/src/sandbox/index.js b/packages/components/src/sandbox/index.js index c52bce90880fa5..2fe01d33f86dbc 100644 --- a/packages/components/src/sandbox/index.js +++ b/packages/components/src/sandbox/index.js @@ -77,6 +77,7 @@ class Sandbox extends Component { } const body = this.iframe.current.contentDocument.body; + if ( ! forceRerender && null !== body.getAttribute( 'data-resizable-iframe-connected' ) @@ -232,7 +233,7 @@ class Sandbox extends Component { title={ title } className="components-sandbox" sandbox="allow-scripts allow-same-origin allow-presentation" - onLoad={ this.trySandbox } + onLoad={ () => this.trySandbox( false ) } onFocus={ onFocus } width={ Math.ceil( this.state.width ) } height={ Math.ceil( this.state.height ) } diff --git a/packages/components/src/sandbox/test/index.js b/packages/components/src/sandbox/test/index.js index 7888082f49459a..4a8343fd5514f4 100644 --- a/packages/components/src/sandbox/test/index.js +++ b/packages/components/src/sandbox/test/index.js @@ -1,8 +1,7 @@ /** * External dependencies */ -import ReactDOM from 'react-dom'; -import { act } from 'react-dom/test-utils'; +import { act, fireEvent, render } from '@testing-library/react'; /** * WordPress dependencies @@ -14,62 +13,67 @@ import { useState } from '@wordpress/element'; */ import Sandbox from '../'; -let container; +describe( 'Sandbox', () => { + const TestWrapper = () => { + const [ html, setHtml ] = useState( + '<iframe class="mock-iframe" src="https://super.embed"></iframe>' + ); -const TestWrapper = () => { - const [ html, setHtml ] = useState( - '<iframe class="mock-iframe" src="https://super.embed"></iframe>' - ); + const updateHtml = () => { + setHtml( + '<iframe class="mock-iframe" src="https://another.super.embed"></iframe>' + ); + }; - const updateHtml = () => { - setHtml( - '<iframe class="mock-iframe" src="https://another.super.embed"></iframe>' + return ( + <div> + <button onClick={ updateHtml } className="mock-button"> + Mock Button + </button> + <Sandbox html={ html } /> + </div> ); }; - return ( - <div> - <button onClick={ updateHtml } className="mock-button"> - Mock Button - </button> - <Sandbox html={ html } /> - </div> - ); -}; - -beforeEach( () => { - container = document.createElement( 'div' ); - document.body.appendChild( container ); -} ); - -afterEach( () => { - document.body.removeChild( container ); - container = null; -} ); + beforeAll( () => { + // MuatationObserver implmentation from JSDom does not work as intended + // with iframes so we need to ignore it for the time being. + jest.spyOn( + global.MutationObserver.prototype, + 'observe' + ).mockImplementation( () => {} ); + } ); -it( 'should rerender with new emdeded content if html prop changes', () => { - act( () => { - ReactDOM.render( <TestWrapper />, container ); + afterAll( () => { + global.MutationObserver.prototype.mockReset(); } ); - const button = container.querySelector( '.mock-button' ); - const iframe = container.querySelector( '.components-sandbox' ); + it( 'should rerender with new emdeded content if html prop changes', () => { + let result; + act( () => { + result = render( <TestWrapper /> ); + } ); - let sandboxedIframe = iframe.contentWindow.document.body.querySelector( - '.mock-iframe' - ); + const iframe = result.container.querySelector( '.components-sandbox' ); - expect( sandboxedIframe.src ).toEqual( 'https://super.embed/' ); + let sandboxedIframe = iframe.contentWindow.document.body.querySelector( + '.mock-iframe' + ); - act( () => { - button.dispatchEvent( - new window.MouseEvent( 'click', { bubbles: true } ) + expect( sandboxedIframe.getAttribute( 'src' ) ).toBe( + 'https://super.embed' ); - } ); - sandboxedIframe = iframe.contentWindow.document.body.querySelector( - '.mock-iframe' - ); + act( () => { + fireEvent.click( result.getByRole( 'button' ) ); + } ); + + sandboxedIframe = iframe.contentWindow.document.body.querySelector( + '.mock-iframe' + ); - expect( sandboxedIframe.src ).toEqual( 'https://another.super.embed/' ); + expect( sandboxedIframe.getAttribute( 'src' ) ).toBe( + 'https://another.super.embed' + ); + } ); } ); diff --git a/packages/components/src/select-control/README.md b/packages/components/src/select-control/README.md index 996756798b64b4..83073594c1dced 100644 --- a/packages/components/src/select-control/README.md +++ b/packages/components/src/select-control/README.md @@ -81,38 +81,42 @@ Use sentences in your menu. Render a user interface to select the size of an image. - import { SelectControl } from '@wordpress/components'; - import { withState } from '@wordpress/compose'; - - const MySelectControl = withState( { - size: '50%', - } )( ( { size, setState } ) => ( - <SelectControl - label="Size" - value={ size } - options={ [ - { label: 'Big', value: '100%' }, - { label: 'Medium', value: '50%' }, - { label: 'Small', value: '25%' }, - ] } - onChange={ ( size ) => { setState( { size } ) } } - /> - ) ); +```jsx +import { SelectControl } from '@wordpress/components'; +import { withState } from '@wordpress/compose'; + +const MySelectControl = withState( { + size: '50%', +} )( ( { size, setState } ) => ( + <SelectControl + label="Size" + value={ size } + options={ [ + { label: 'Big', value: '100%' }, + { label: 'Medium', value: '50%' }, + { label: 'Small', value: '25%' }, + ] } + onChange={ ( size ) => { setState( { size } ) } } + /> +) ); +``` Render a user interface to select multiple users from a list. - <SelectControl - multiple - label={ __( 'Select some users:' ) } - value={ this.state.users } // e.g: value = [ 'a', 'c' ] - onChange={ ( users ) => { this.setState( { users } ) } } - options={ [ - { value: null, label: 'Select a User', disabled: true }, - { value: 'a', label: 'User A' }, - { value: 'b', label: 'User B' }, - { value: 'c', label: 'User c' }, - ] } - /> +```jsx +<SelectControl + multiple + label={ __( 'Select some users:' ) } + value={ this.state.users } // e.g: value = [ 'a', 'c' ] + onChange={ ( users ) => { this.setState( { users } ) } } + options={ [ + { value: null, label: 'Select a User', disabled: true }, + { value: 'a', label: 'User A' }, + { value: 'b', label: 'User B' }, + { value: 'c', label: 'User c' }, + ] } +/> +``` ### Props diff --git a/packages/components/src/slot-fill/bubbles-virtually/slot-fill-provider.js b/packages/components/src/slot-fill/bubbles-virtually/slot-fill-provider.js index d487d98fbfa9a1..6d4b046a6271cf 100644 --- a/packages/components/src/slot-fill/bubbles-virtually/slot-fill-provider.js +++ b/packages/components/src/slot-fill/bubbles-virtually/slot-fill-provider.js @@ -25,11 +25,10 @@ function useSlotRegistry() { const unregisterSlot = useCallback( ( name, ref ) => { setSlots( ( prevSlots ) => { - // eslint-disable-next-line no-unused-vars const { [ name ]: slot, ...nextSlots } = prevSlots; // Make sure we're not unregistering a slot registered by another element // See https://github.com/WordPress/gutenberg/pull/19242#issuecomment-590295412 - if ( slot.ref === ref ) { + if ( slot?.ref === ref ) { return nextSlots; } return prevSlots; diff --git a/packages/components/src/slot-fill/stories/index.js b/packages/components/src/slot-fill/stories/index.js index 035defa5eb4f6e..2af19ecf012c31 100644 --- a/packages/components/src/slot-fill/stories/index.js +++ b/packages/components/src/slot-fill/stories/index.js @@ -16,9 +16,6 @@ import { Slot, Fill, Provider } from '../'; export default { title: 'Components/SlotFill', component: Slot, - parameters: { - storyshots: { disable: true }, - }, }; export const _default = () => { diff --git a/packages/components/src/slot-fill/test/__snapshots__/slot.js.snap b/packages/components/src/slot-fill/test/__snapshots__/slot.js.snap index 79b43ad4c65c07..5cffdf5ec3f6ca 100644 --- a/packages/components/src/slot-fill/test/__snapshots__/slot.js.snap +++ b/packages/components/src/slot-fill/test/__snapshots__/slot.js.snap @@ -1,128 +1,166 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Slot bubblesVirtually false should subsume another slot by the same name 1`] = ` -Array [ +<div> <div data-position="first" - />, + /> <div data-position="second" > Content - </div>, -] + </div> +</div> `; exports[`Slot bubblesVirtually false should subsume another slot by the same name 2`] = ` -Array [ +<div> <div data-position="first" - />, + /> <div data-position="second" > Content - </div>, -] + </div> +</div> +`; + +exports[`Slot bubblesVirtually false should unmount two slots with the same name 1`] = ` +<div> + <div + data-position="first" + /> + <div + data-position="second" + /> +</div> `; exports[`Slot bubblesVirtually true should subsume another slot by the same name 1`] = ` -Array [ +<div> <div data-position="first" > <div /> - </div>, + </div> <div data-position="second" > - <div /> - </div>, -] + <div> + Content + </div> + </div> +</div> `; exports[`Slot bubblesVirtually true should subsume another slot by the same name 2`] = ` -Array [ +<div> <div data-position="first" - />, + /> <div data-position="second" > - <div /> - </div>, -] + <div> + Content + </div> + </div> +</div> +`; + +exports[`Slot bubblesVirtually true should unmount two slots with the same name 1`] = ` +<div> + <div + data-position="first" + /> + <div + data-position="second" + /> +</div> `; exports[`Slot should re-render Slot when not bubbling virtually 1`] = ` -Array [ +<div> <div> 1 - </div>, + </div> <button - onClick={[Function]} type="button" - />, -] + /> +</div> `; exports[`Slot should re-render Slot when not bubbling virtually 2`] = ` -Array [ +<div> <div> 2 - </div>, + </div> <button - onClick={[Function]} type="button" - />, -] + /> +</div> `; exports[`Slot should render a Fill containing an array 1`] = ` <div> - <span /> - <div /> - text + <div> + <span /> + <div /> + text + </div> </div> `; exports[`Slot should render a Fill containing an element 1`] = ` <div> - <span /> + <div> + <span /> + </div> </div> `; exports[`Slot should render a string Fill 1`] = ` <div> - content + <div> + content + </div> </div> `; exports[`Slot should render a string Fill with HTML wrapper when render props used 1`] = ` <div> - <blockquote> - content - </blockquote> + <div> + <blockquote> + content + </blockquote> + </div> </div> `; -exports[`Slot should render empty Fills 1`] = `<div />`; +exports[`Slot should render empty Fills 1`] = ` +<div> + <div /> +</div> +`; -exports[`Slot should render empty Fills without HTML wrapper when render props used 1`] = `<div />`; +exports[`Slot should render empty Fills without HTML wrapper when render props used 1`] = ` +<div> + <div /> +</div> +`; exports[`Slot should render in expected order 1`] = ` -Array [ +<div> <div> first second - </div>, + </div> <button - onClick={[Function]} type="button" - />, + /> <button - onClick={[Function]} type="button" - />, -] + /> +</div> `; diff --git a/packages/components/src/slot-fill/test/slot.js b/packages/components/src/slot-fill/test/slot.js index db935e6bc2ed29..398ea965924458 100644 --- a/packages/components/src/slot-fill/test/slot.js +++ b/packages/components/src/slot-fill/test/slot.js @@ -2,7 +2,7 @@ * External dependencies */ import { isEmpty } from 'lodash'; -import ReactTestRenderer from 'react-test-renderer'; +import { render, fireEvent } from '@testing-library/react'; /** * Internal dependencies @@ -38,33 +38,33 @@ class Filler extends Component { describe( 'Slot', () => { it( 'should render empty Fills', () => { - const tree = ReactTestRenderer.create( + const { container } = render( <Provider> <div> <Slot name="chicken" /> </div> <Fill name="chicken" /> </Provider> - ).toJSON(); + ); - expect( tree ).toMatchSnapshot(); + expect( container ).toMatchSnapshot(); } ); it( 'should render a string Fill', () => { - const tree = ReactTestRenderer.create( + const { container } = render( <Provider> <div> <Slot name="chicken" /> </div> <Fill name="chicken">content</Fill> </Provider> - ).toJSON(); + ); - expect( tree ).toMatchSnapshot(); + expect( container ).toMatchSnapshot(); } ); it( 'should render a Fill containing an element', () => { - const tree = ReactTestRenderer.create( + const { container } = render( <Provider> <div> <Slot name="chicken" /> @@ -73,13 +73,13 @@ describe( 'Slot', () => { <span /> </Fill> </Provider> - ).toJSON(); + ); - expect( tree ).toMatchSnapshot(); + expect( container ).toMatchSnapshot(); } ); it( 'should render a Fill containing an array', () => { - const tree = ReactTestRenderer.create( + const { container } = render( <Provider> <div> <Slot name="chicken" /> @@ -88,15 +88,15 @@ describe( 'Slot', () => { { [ <span key="1" />, <div key="2" />, 'text' ] } </Fill> </Provider> - ).toJSON(); + ); - expect( tree ).toMatchSnapshot(); + expect( container ).toMatchSnapshot(); } ); it( 'calls the functions passed as the Slot’s fillProps in the Fill', () => { const onClose = jest.fn(); - const testInstance = ReactTestRenderer.create( + const { getByText } = render( <Provider> <Slot name="chicken" fillProps={ { onClose } } /> <Fill name="chicken"> @@ -107,15 +107,15 @@ describe( 'Slot', () => { } } </Fill> </Provider> - ).root; + ); - testInstance.findByType( 'button' ).props.onClick(); + fireEvent.click( getByText( 'Click me' ) ); expect( onClose ).toHaveBeenCalledTimes( 1 ); } ); it( 'should render empty Fills without HTML wrapper when render props used', () => { - const tree = ReactTestRenderer.create( + const { container } = render( <Provider> <div> <Slot name="chicken"> @@ -128,13 +128,13 @@ describe( 'Slot', () => { </div> <Fill name="chicken" /> </Provider> - ).toJSON(); + ); - expect( tree ).toMatchSnapshot(); + expect( container ).toMatchSnapshot(); } ); it( 'should render a string Fill with HTML wrapper when render props used', () => { - const tree = ReactTestRenderer.create( + const { container } = render( <Provider> <div> <Slot name="chicken"> @@ -145,13 +145,13 @@ describe( 'Slot', () => { </div> <Fill name="chicken">content</Fill> </Provider> - ).toJSON(); + ); - expect( tree ).toMatchSnapshot(); + expect( container ).toMatchSnapshot(); } ); it( 'should re-render Slot when not bubbling virtually', () => { - const testRenderer = ReactTestRenderer.create( + const { container, getByRole } = render( <Provider> <div> <Slot name="egg" /> @@ -160,15 +160,15 @@ describe( 'Slot', () => { </Provider> ); - expect( testRenderer.toJSON() ).toMatchSnapshot(); + expect( container ).toMatchSnapshot(); - testRenderer.root.findByType( 'button' ).props.onClick(); + fireEvent.click( getByRole( 'button' ) ); - expect( testRenderer.toJSON() ).toMatchSnapshot(); + expect( container ).toMatchSnapshot(); } ); it( 'should render in expected order', () => { - const testRenderer = ReactTestRenderer.create( + const { container, rerender } = render( <Provider> <div key="slot"> <Slot name="egg" /> @@ -176,7 +176,7 @@ describe( 'Slot', () => { </Provider> ); - testRenderer.update( + rerender( <Provider> <div key="slot"> <Slot name="egg" /> @@ -186,7 +186,7 @@ describe( 'Slot', () => { </Provider> ); - testRenderer.update( + rerender( <Provider> <div key="slot"> <Slot name="egg" /> @@ -195,7 +195,7 @@ describe( 'Slot', () => { </Provider> ); - testRenderer.update( + rerender( <Provider> <div key="slot"> <Slot name="egg" /> @@ -205,14 +205,14 @@ describe( 'Slot', () => { </Provider> ); - expect( testRenderer.toJSON() ).toMatchSnapshot(); + expect( container ).toMatchSnapshot(); } ); describe.each( [ false, true ] )( 'bubblesVirtually %p', ( bubblesVirtually ) => { it( 'should subsume another slot by the same name', () => { - const testRenderer = ReactTestRenderer.create( + const { container, rerender } = render( <Provider> <div data-position="first"> <Slot @@ -225,7 +225,7 @@ describe( 'Slot', () => { </Provider> ); - testRenderer.update( + rerender( <Provider> <div data-position="first"> <Slot @@ -243,9 +243,9 @@ describe( 'Slot', () => { </Provider> ); - expect( testRenderer.toJSON() ).toMatchSnapshot(); + expect( container ).toMatchSnapshot(); - testRenderer.update( + rerender( <Provider> <div data-position="first"></div> <div data-position="second"> @@ -258,7 +258,47 @@ describe( 'Slot', () => { </Provider> ); - expect( testRenderer.toJSON() ).toMatchSnapshot(); + expect( container ).toMatchSnapshot(); + } ); + + it( 'should unmount two slots with the same name', () => { + const { rerender, container } = render( + <Provider> + <div data-position="first"> + <Slot + name="egg" + bubblesVirtually={ bubblesVirtually } + /> + </div> + <div data-position="second"> + <Slot + name="egg" + bubblesVirtually={ bubblesVirtually } + /> + </div> + <Fill name="egg">Content</Fill> + </Provider> + ); + rerender( + <Provider> + <div data-position="first"> + <Slot + name="egg" + bubblesVirtually={ bubblesVirtually } + /> + </div> + <div data-position="second" /> + <Fill name="egg">Content</Fill> + </Provider> + ); + rerender( + <Provider> + <div data-position="first" /> + <div data-position="second" /> + <Fill name="egg">Content</Fill> + </Provider> + ); + expect( container ).toMatchSnapshot(); } ); } ); diff --git a/packages/components/src/snackbar/index.js b/packages/components/src/snackbar/index.js index 45b8bd8e24a946..4c5ae0ac7e5b05 100644 --- a/packages/components/src/snackbar/index.js +++ b/packages/components/src/snackbar/index.js @@ -77,7 +77,7 @@ function Snackbar( tabIndex="0" role="button" onKeyPress={ onRemove } - label={ __( 'Dismiss this notice' ) } + aria-label={ __( 'Dismiss this notice' ) } > <div className="components-snackbar__content"> { children } diff --git a/packages/components/src/tab-panel/index.js b/packages/components/src/tab-panel/index.js index 1940ef4de9c019..682ac3fcfe1029 100644 --- a/packages/components/src/tab-panel/index.js +++ b/packages/components/src/tab-panel/index.js @@ -103,7 +103,6 @@ class TabPanel extends Component { role="tabpanel" id={ selectedId + '-view' } className="components-tab-panel__tab-content" - tabIndex="0" > { this.props.children( selectedTab ) } </div> diff --git a/packages/components/src/tab-panel/style.scss b/packages/components/src/tab-panel/style.scss index f2048be4a19394..fbc051f407e45c 100644 --- a/packages/components/src/tab-panel/style.scss +++ b/packages/components/src/tab-panel/style.scss @@ -6,28 +6,37 @@ .components-tab-panel__tabs-item { background: transparent; border: none; - border-radius: 0; box-shadow: none; + border-radius: 0; cursor: pointer; - height: 50px; - padding: 3px 15px; // Use padding to offset the is-active border, this benefits Windows High Contrast mode + height: $grid-unit-60; + padding: 3px $grid-unit-20; // Use padding to offset the is-active border, this benefits Windows High Contrast mode margin-left: 0; - font-weight: 400; - @include square-style__neutral; + font-weight: 500; transition: box-shadow 0.1s linear; + box-sizing: border-box; + + // This pseudo-element "duplicates" the tab label and sets the text to bold. + // This ensures that the tab doesn't change width when selected. + // See: https://github.com/WordPress/gutenberg/pull/9793 + &::after { + content: attr(data-label); + display: block; + height: 0; + overflow: hidden; + speak: none; + visibility: hidden; + } - &:focus:enabled { - color: $dark-gray-900; - outline-offset: -1px; - outline: 1px dotted $dark-gray-500; + &:focus:not(:disabled) { + box-shadow: inset 0 $border-width-focus $theme-color; } - &:focus:enabled, + &.is-active { - box-shadow: inset 0 -3px theme(outlines); - font-weight: 600; + // The transparent shadow ensures no jumpiness when focus animates on an active tab. + box-shadow: inset 0 0 0 $border-width-focus transparent, inset 0 0 -$border-width-tab 0 0 $theme-color; position: relative; - background: transparent; // This border appears in Windows High Contrast mode instead of the box-shadow. &::before { @@ -37,8 +46,15 @@ bottom: 1px; right: 0; left: 0; - border-bottom: 3px solid transparent; + border-bottom: $border-width-tab solid transparent; } } + &:focus { + box-shadow: inset 0 0 0 $border-width-focus $theme-color; + } + + &.is-active:focus { + box-shadow: inset 0 0 0 $border-width-focus $theme-color, inset 0 0 -$border-width-tab 0 0 $theme-color; + } } diff --git a/packages/components/src/text/README.md b/packages/components/src/text/README.md index 806c60d45a06bc..4a659b34fa4ccc 100644 --- a/packages/components/src/text/README.md +++ b/packages/components/src/text/README.md @@ -1,18 +1,54 @@ # Text -A text component for styling text. +A component for rendering text. ## Usage ```jsx -import {Text} from '@wordpress/components'; +import { Text } from '@wordpress/components'; const HeroPanel = () => ( <> - <Text variant="title.large" as="h1">Hello World!</Text> + <Text variant="title.large" as="h1"> + Hello World! + </Text> <Text variant="body">Greetings to you!</Text> </> ); ``` -> For most use-cases you can use this component instead of a `h1`, `h2`, `h3`, `h4`, `h5`, `h6` or `p`. +## Props + +The component accepts the following props: + +#### as + +Determines the HTML selector for the text. + +For most use-cases you can use this component instead of a `h1`, `h2`, `h3`, `h4`, `h5`, `h6` or `p`. + +- Type: `String` +- Required: No +- Default: '' + +#### variant + +Determines the style for the text. Available variants: + +- `title` +- `title.large` +- `title.medium` +- `title.small` +- `subtitle` +- `subtitle.large` +- `subtitle.small` +- `body` +- `body.large` +- `body.small` +- `button` +- `caption` +- `label` + +* Type: `String` +* Required: No +* Default: 'body' diff --git a/packages/components/src/text/index.js b/packages/components/src/text/index.js index c4ae06e2b4f97f..e502e39a59c49a 100644 --- a/packages/components/src/text/index.js +++ b/packages/components/src/text/index.js @@ -1 +1,19 @@ -export * from './text.styles'; +/** + * External dependencies + */ +import styled from '@emotion/styled'; + +/** + * Internal dependencies + */ +import { text } from './styles/text-mixins'; + +const Text = styled.p( + ` + box-sizing: border-box; + margin: 0; +`, + text +); + +export default Text; diff --git a/packages/components/src/text/text.styles.native.js b/packages/components/src/text/index.native.js similarity index 51% rename from packages/components/src/text/text.styles.native.js rename to packages/components/src/text/index.native.js index 2304de2efa62f3..8a52d4056d5578 100644 --- a/packages/components/src/text/text.styles.native.js +++ b/packages/components/src/text/index.native.js @@ -6,6 +6,8 @@ import styled from '@emotion/native'; /** * Internal dependencies */ -import { text } from './mixins'; +import { text } from './styles/text-mixins'; -export const __experimentalText = styled.Text( text ); +const Text = styled.Text( text ); + +export default Text; diff --git a/packages/components/src/text/stories/index.js b/packages/components/src/text/stories/index.js index f1dca3b2c819b6..aeb3cd330fdd3a 100644 --- a/packages/components/src/text/stories/index.js +++ b/packages/components/src/text/stories/index.js @@ -1,10 +1,10 @@ /** * Internal dependencies */ -import { __experimentalText as Text } from '../text.styles'; +import Text from '../index'; export default { - title: 'Components/Experimental/Text', + title: 'Components/Text', component: Text, }; @@ -28,31 +28,3 @@ export const _default = () => ( <Text variant="label">Label</Text> </> ); - -export const TitleLarge = () => ( - <Text variant="title.large" as="h1"> - Title Large - </Text> -); -export const TitleMedium = () => ( - <Text variant="title.medium" as="h2"> - Title Medium - </Text> -); -export const TitleSmall = () => ( - <Text variant="title.small" as="h3"> - Title Small - </Text> -); - -export const Subtitle = () => <Text variant="subtitle">Subtitle</Text>; -export const SubtitleSmall = () => ( - <Text variant="subtitle.small">Subtitle Small</Text> -); - -export const Body = () => <Text variant="body">Body</Text>; -export const BodySmall = () => <Text variant="body.small">Body Small</Text>; - -export const Button = () => <Text variant="button">Button</Text>; -export const Caption = () => <Text variant="caption">Caption</Text>; -export const Label = () => <Text variant="label">Label</Text>; diff --git a/packages/components/src/text/styles/emotion-css.js b/packages/components/src/text/styles/emotion-css.js new file mode 100644 index 00000000000000..c86ee0154e7630 --- /dev/null +++ b/packages/components/src/text/styles/emotion-css.js @@ -0,0 +1,6 @@ +/** + * External dependencies + */ +import { css } from '@emotion/core'; + +export default css; diff --git a/packages/components/src/text/styles/emotion-css.native.js b/packages/components/src/text/styles/emotion-css.native.js new file mode 100644 index 00000000000000..11ea92e4e705c3 --- /dev/null +++ b/packages/components/src/text/styles/emotion-css.native.js @@ -0,0 +1,6 @@ +/** + * External dependencies + */ +import { css } from '@emotion/native'; + +export default css; diff --git a/packages/components/src/text/font-family.js b/packages/components/src/text/styles/font-family.js similarity index 100% rename from packages/components/src/text/font-family.js rename to packages/components/src/text/styles/font-family.js diff --git a/packages/components/src/text/font-family.native.js b/packages/components/src/text/styles/font-family.native.js similarity index 100% rename from packages/components/src/text/font-family.native.js rename to packages/components/src/text/styles/font-family.native.js diff --git a/packages/components/src/text/mixins.js b/packages/components/src/text/styles/text-mixins.js similarity index 87% rename from packages/components/src/text/mixins.js rename to packages/components/src/text/styles/text-mixins.js index dfa3dfecc38979..d2463e80310a49 100644 --- a/packages/components/src/text/mixins.js +++ b/packages/components/src/text/styles/text-mixins.js @@ -1,11 +1,8 @@ -/** - * External dependencies - */ -import css from '@emotion/css'; /** * Internal dependencies */ import { fontFamily } from './font-family'; +import css from './emotion-css'; const fontWeightNormal = `font-weight: 400;`; const fontWeightSemibold = `font-weight: 600;`; @@ -78,13 +75,13 @@ const label = ` `; /** - * @typedef {'title.large'|'title.medium'|'title.small'|'subtitle'|'subtitle.small'|'body'|'body.small'|'button'|'caption'|'label'} TextVariant + * @typedef {'title.large'|'title.medium'|'title.small'|'subtitle'|'subtitle.small'|'body'|'body.large'|'body.small'|'button'|'caption'|'label'} TextVariant */ /** * @param {TextVariant} variantName */ -const variant = ( variantName ) => { +const variant = ( variantName = 'body' ) => { switch ( variantName ) { case 'title.large': return css` @@ -114,6 +111,10 @@ const variant = ( variantName ) => { `; case 'body': + return css` + ${body} + `; + case 'body.large': return css` ${body} ${bodyLarge} @@ -137,7 +138,7 @@ const variant = ( variantName ) => { /** * @typedef {Object} TextProps - * @property {TextVariant} variant + * @property {TextVariant} variant one of TextVariant to be used */ /** diff --git a/packages/components/src/text/test/index.js b/packages/components/src/text/test/index.js new file mode 100644 index 00000000000000..dfa504018ed5dd --- /dev/null +++ b/packages/components/src/text/test/index.js @@ -0,0 +1,94 @@ +/** + * External dependencies + */ +import { render, unmountComponentAtNode } from 'react-dom'; +import { act } from 'react-dom/test-utils'; + +/** + * Internal dependencies + */ +import Text from '../'; + +let container = null; + +beforeEach( () => { + container = document.createElement( 'div' ); + document.body.appendChild( container ); +} ); + +afterEach( () => { + unmountComponentAtNode( container ); + container.remove(); + container = null; +} ); + +function getTextStyle( node ) { + const text = node || container.children[ 0 ]; + return window.getComputedStyle( text ); +} + +describe( 'Text', () => { + describe( 'Basic rendering', () => { + it( 'should render', () => { + act( () => { + render( <Text>Hello</Text>, container ); + } ); + + const [ text ] = container.children; + + expect( text.innerHTML ).toBe( 'Hello' ); + } ); + + it( 'should render as a <p>, by default', () => { + act( () => { + render( <Text />, container ); + } ); + + const [ text ] = container.children; + + expect( text.tagName ).toBe( 'P' ); + } ); + + it( 'should render as another selector, if specified', () => { + act( () => { + render( + <> + <Text as="h1" /> + <Text as="h2" /> + <Text as="span" /> + <Text as="div" /> + </>, + container + ); + } ); + + const [ h1, h2, span, div ] = container.children; + + expect( h1.tagName ).toBe( 'H1' ); + expect( h2.tagName ).toBe( 'H2' ); + expect( span.tagName ).toBe( 'SPAN' ); + expect( div.tagName ).toBe( 'DIV' ); + } ); + } ); + + describe( 'Variants', () => { + it( 'should render with specified variantion styles', () => { + act( () => { + render( + <> + <Text>Base</Text> + <Text variant="title.large">Title Large</Text> + <Text variant="caption">Caption</Text> + </>, + container + ); + } ); + + const [ base, title, caption ] = container.children; + + expect( getTextStyle( base ).fontSize ).toBeFalsy(); + expect( getTextStyle( title ).fontSize ).toBe( '32px' ); + expect( getTextStyle( caption ).fontSize ).toBe( '12px' ); + } ); + } ); +} ); diff --git a/packages/components/src/text/text.styles.js b/packages/components/src/text/text.styles.js deleted file mode 100644 index 67545507f0d0b5..00000000000000 --- a/packages/components/src/text/text.styles.js +++ /dev/null @@ -1,11 +0,0 @@ -/** - * External dependencies - */ -import styled from '@emotion/styled'; - -/** - * Internal dependencies - */ -import { text } from './mixins'; - -export const __experimentalText = styled.p( `margin: 0;`, text ); diff --git a/packages/components/src/toolbar-button/index.js b/packages/components/src/toolbar-button/index.js index 4d56476caadc8b..347fd5fd0d7e60 100644 --- a/packages/components/src/toolbar-button/index.js +++ b/packages/components/src/toolbar-button/index.js @@ -48,8 +48,9 @@ function ToolbarButton( { isPressed={ props.isActive } disabled={ props.isDisabled } { ...extraProps } - /> - { children } + > + { children } + </Button> </ToolbarButtonContainer> ); } diff --git a/packages/components/src/toolbar-button/stories/index.js b/packages/components/src/toolbar-button/stories/index.js new file mode 100644 index 00000000000000..1bb0475003e161 --- /dev/null +++ b/packages/components/src/toolbar-button/stories/index.js @@ -0,0 +1,23 @@ +/** + * External dependencies + */ +import { text } from '@storybook/addon-knobs'; + +/** + * Internal dependencies + */ +import { Toolbar } from '../../'; +import ToolbarButton from '../'; + +export default { title: 'Components/ToolbarButton', component: ToolbarButton }; + +export const _default = () => { + const label = text( 'Label', 'This is an example label.' ); + const icon = text( 'Icon', 'wordpress' ); + + return ( + <Toolbar __experimentalAccessibilityLabel="Example Toolbar"> + <ToolbarButton icon={ icon } label={ label } /> + </Toolbar> + ); +}; diff --git a/packages/components/src/toolbar-group/style.scss b/packages/components/src/toolbar-group/style.scss index da98306f2c402f..a804663d4ef793 100644 --- a/packages/components/src/toolbar-group/style.scss +++ b/packages/components/src/toolbar-group/style.scss @@ -1,9 +1,10 @@ .components-toolbar-group { - border: $border-width solid $light-gray-500; + min-height: $block-toolbar-height; + border-right: $border-width solid $dark-gray-primary; background-color: $white; - display: flex; + display: inline-flex; flex-shrink: 0; - margin-right: -$border-width; + flex-wrap: wrap; & & { border-width: 0; @@ -16,11 +17,14 @@ // Legacy toolbar group // External code references to it, so we can't change it? .components-toolbar { + min-height: $block-toolbar-height; margin: 0; - border: $border-width solid $light-gray-500; + border: $border-width solid $dark-gray-primary; + border-radius: $radius-block-ui; background-color: $white; - display: flex; + display: inline-flex; flex-shrink: 0; + flex-wrap: wrap; } div.components-toolbar { @@ -54,3 +58,60 @@ div.components-toolbar { } } } + +// Size multiple sequential buttons to be optically balanced. +// Icons are 36px, as set by a 24px icon and 12px padding. +.components-accessible-toolbar .components-toolbar-group > .components-button.components-button.has-icon, +.components-toolbar div > .components-button.components-button.has-icon { + min-width: $block-toolbar-height - $grid-unit-15; + padding-left: $grid-unit-15 / 2; // 6px. + padding-right: $grid-unit-15 / 2; + + svg { + min-width: $button-size-small; // This is the optimal icon size, and we size the whole button after this. + } + + &::before { + left: 2px; + right: 2px; + } +} + +// First button in a group. +.components-accessible-toolbar .components-toolbar-group > .components-button:first-child.has-icon, +.components-toolbar div:first-child .components-button.has-icon { + min-width: $block-toolbar-height - $grid-unit-15 / 2; + padding-left: $grid-unit-15 - $border-width; + padding-right: $grid-unit-15 / 2; + + &::before { + left: $grid-unit-10; + right: 2px; + } +} + +// Last button in a group. +.components-accessible-toolbar .components-toolbar-group > .components-button:last-child.has-icon, +.components-toolbar div:last-child .components-button.has-icon { + min-width: $block-toolbar-height - $grid-unit-15 / 2; + padding-left: $grid-unit-15 / 2; + padding-right: $grid-unit-15 - $border-width; + + &::before { + left: 2px; + right: $grid-unit-10; + } +} + +// Single buttons should remain 48px. +.components-accessible-toolbar .components-toolbar-group > .components-button:first-child:last-child.has-icon, +.components-toolbar div:first-child:last-child > .components-button.has-icon { + min-width: $block-toolbar-height; + padding-left: $grid-unit-15; + padding-right: $grid-unit-15; + + &::before { + left: $grid-unit-10; + right: $grid-unit-10; + } +} diff --git a/packages/components/src/toolbar-group/test/index.js b/packages/components/src/toolbar-group/test/index.js index c2aa53a165f17e..4bd6951caf477b 100644 --- a/packages/components/src/toolbar-group/test/index.js +++ b/packages/components/src/toolbar-group/test/index.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { mount } from 'enzyme'; +import { fireEvent, render } from '@testing-library/react'; /** * Internal dependencies @@ -11,13 +11,15 @@ import ToolbarGroup from '../'; describe( 'ToolbarGroup', () => { describe( 'basic rendering', () => { it( 'should render an empty node, when controls are not passed', () => { - const wrapper = mount( <ToolbarGroup /> ); - expect( wrapper.html() ).toBeNull(); + const { container } = render( <ToolbarGroup /> ); + + expect( container.innerHTML ).toBe( '' ); } ); it( 'should render an empty node, when controls are empty', () => { - const wrapper = mount( <ToolbarGroup controls={ [] } /> ); - expect( wrapper.html() ).toBeNull(); + const { container } = render( <ToolbarGroup controls={ [] } /> ); + + expect( container.innerHTML ).toBe( '' ); } ); it( 'should render a list of controls with buttons', () => { @@ -30,15 +32,16 @@ describe( 'ToolbarGroup', () => { isActive: false, }, ]; - const wrapper = mount( <ToolbarGroup controls={ controls } /> ); - const button = wrapper - .find( '[aria-label="WordPress"]' ) - .hostNodes(); - expect( button.props() ).toMatchObject( { - 'aria-label': 'WordPress', - 'aria-pressed': false, - type: 'button', - } ); + + const { getByLabelText } = render( + <ToolbarGroup controls={ controls } /> + ); + + const toolbarButton = getByLabelText( 'WordPress' ); + expect( toolbarButton.getAttribute( 'aria-pressed' ) ).toBe( + 'false' + ); + expect( toolbarButton.getAttribute( 'type' ) ).toBe( 'button' ); } ); it( 'should render a list of controls with buttons and active control', () => { @@ -51,15 +54,16 @@ describe( 'ToolbarGroup', () => { isActive: true, }, ]; - const wrapper = mount( <ToolbarGroup controls={ controls } /> ); - const button = wrapper - .find( '[aria-label="WordPress"]' ) - .hostNodes(); - expect( button.props() ).toMatchObject( { - 'aria-label': 'WordPress', - 'aria-pressed': true, - type: 'button', - } ); + + const { getByLabelText } = render( + <ToolbarGroup controls={ controls } /> + ); + + const toolbarButton = getByLabelText( 'WordPress' ); + expect( toolbarButton.getAttribute( 'aria-pressed' ) ).toBe( + 'true' + ); + expect( toolbarButton.getAttribute( 'type' ) ).toBe( 'button' ); } ); it( 'should render a nested list of controls with separator between', () => { @@ -80,14 +84,15 @@ describe( 'ToolbarGroup', () => { ], ]; - const wrapper = mount( <ToolbarGroup controls={ controls } /> ); - const buttons = wrapper.find( 'button' ).hostNodes(); - const hasLeftDivider = wrapper - .find( '.has-left-divider' ) - .hostNodes(); + const { container, getAllByRole } = render( + <ToolbarGroup controls={ controls } /> + ); + + const buttons = getAllByRole( 'button' ); expect( buttons ).toHaveLength( 2 ); - expect( hasLeftDivider ).toHaveLength( 1 ); - expect( hasLeftDivider.html() ).toContain( buttons.at( 1 ).html() ); + expect( + container.querySelector( '.has-left-divider button' ) + ).toBe( buttons[ 1 ] ); } ); it( 'should call the clickHandler on click.', () => { @@ -100,11 +105,11 @@ describe( 'ToolbarGroup', () => { isActive: true, }, ]; - const wrapper = mount( <ToolbarGroup controls={ controls } /> ); - const button = wrapper - .find( '[aria-label="WordPress"]' ) - .hostNodes(); - button.simulate( 'click' ); + const { getByLabelText } = render( + <ToolbarGroup controls={ controls } /> + ); + + fireEvent.click( getByLabelText( 'WordPress' ) ); expect( clickHandler ).toHaveBeenCalledTimes( 1 ); } ); } ); diff --git a/packages/components/src/toolbar-group/toolbar-group-collapsed.native.js b/packages/components/src/toolbar-group/toolbar-group-collapsed.native.js index a890645928854a..411a4e6edbd604 100644 --- a/packages/components/src/toolbar-group/toolbar-group-collapsed.native.js +++ b/packages/components/src/toolbar-group/toolbar-group-collapsed.native.js @@ -1,10 +1,36 @@ +/** + * External dependencies + */ +import { View } from 'react-native'; +/** + * WordPress dependencies + */ +import { withPreferredColorScheme } from '@wordpress/compose'; /** * Internal dependencies */ import DropdownMenu from '../dropdown-menu'; +import styles from './style.scss'; -function ToolbarGroupCollapsed( { controls = [], ...props } ) { - return <DropdownMenu controls={ controls } { ...props } />; +function ToolbarGroupCollapsed( { + controls = [], + getStylesFromColorScheme, + passedStyle, + ...props +} ) { + return ( + <View + style={ [ + getStylesFromColorScheme( + styles.container, + styles.containerDark + ), + passedStyle, + ] } + > + <DropdownMenu controls={ controls } { ...props } /> + </View> + ); } -export default ToolbarGroupCollapsed; +export default withPreferredColorScheme( ToolbarGroupCollapsed ); diff --git a/packages/components/src/toolbar/stories/index.js b/packages/components/src/toolbar/stories/index.js index d4edace706f17a..2749329089b775 100644 --- a/packages/components/src/toolbar/stories/index.js +++ b/packages/components/src/toolbar/stories/index.js @@ -126,3 +126,57 @@ export const withoutGroup = () => { ); }; /* eslint-enable no-restricted-syntax */ + +export const toolbars = () => { + return ( + <div> + <div style={ { padding: '20px' } }> + <h2>Icon-only Toolbar</h2> + <Toolbar> + <ToolbarButton icon={ formatBold } title="Bold" /> + <ToolbarButton + icon={ formatItalic } + title="Italic" + isActive + /> + <ToolbarButton icon={ link } title="Link" /> + </Toolbar> + </div> + + <div style={ { padding: '20px' } }> + <h2>Text-only Toolbar</h2> + <Toolbar> + <ToolbarButton>Bold Format</ToolbarButton> + <ToolbarButton isActive>Italic Format</ToolbarButton> + <ToolbarButton>Link Format</ToolbarButton> + </Toolbar> + </div> + + <div style={ { padding: '20px' } }> + <h2>Text and Icon Toolbar</h2> + <Toolbar> + <ToolbarButton icon={ formatBold } title="Bold" /> + <ToolbarButton isActive>Bold Format</ToolbarButton> + <ToolbarButton icon={ formatItalic } title="Italic" /> + <ToolbarButton>Italic Format</ToolbarButton> + <ToolbarButton icon={ link } title="Link" /> + <ToolbarButton>Link Format</ToolbarButton> + </Toolbar> + </div> + + <div style={ { padding: '20px' } }> + <h2>Single Icon Button Toolbar</h2> + <Toolbar> + <ToolbarButton icon={ formatBold } title="Bold" /> + </Toolbar> + </div> + + <div style={ { padding: '20px' } }> + <h2>Single Text Button toolbar</h2> + <Toolbar> + <ToolbarButton>Bold Toolbar</ToolbarButton> + </Toolbar> + </div> + </div> + ); +}; diff --git a/packages/components/src/toolbar/style.scss b/packages/components/src/toolbar/style.scss index 2dc89b9b4e5f8f..fdbcccb3f20294 100644 --- a/packages/components/src/toolbar/style.scss +++ b/packages/components/src/toolbar/style.scss @@ -1,11 +1,106 @@ .components-accessible-toolbar { - // Required for IE11. display: inline-flex; + border: $border-width solid $dark-gray-primary; + border-radius: $radius-block-ui; + flex-shrink: 0; - // IE11 doesn't read rules inside this query. They are applied only to modern browsers. - @supports (position: sticky) { - display: flex; + .components-toolbar-group:last-child { + border-right: none; } +} - flex-shrink: 0; +.components-accessible-toolbar, +.components-toolbar { + .components-button { + position: relative; + height: $block-toolbar-height; + z-index: 1; + + // Give all buttons extra padding to fit text. + padding-left: $grid-unit-20; + padding-right: $grid-unit-20; + + // Don't show the focus inherited by the Button component. + &:focus:enabled { + box-shadow: none; + outline: none; + } + + // Focus and toggle pseudo elements. + &::before { + content: ""; + position: absolute; + display: block; + border-radius: $radius-block-ui; + height: 32px; + min-width: 32px; + + // Position the focus rectangle. + left: $grid-unit-10; + right: $grid-unit-10; + z-index: -1; + + // Animate in. + animation: components-button__appear-animation 0.1s ease; + animation-fill-mode: forwards; + @include reduce-motion("animation"); + } + + svg { + position: relative; + + // Center the icon inside. + margin-left: auto; + margin-right: auto; + } + + // Toggled style. + &.is-pressed { + background: transparent; + + &:hover { + background: transparent; + } + + &::before { + background: $dark-gray-primary; + } + } + + // Focus style. + &:focus::before { + @include block-toolbar-button-style__focus(); + } + + // Ensure the icon buttons remain square. + &.has-icon { + // Reduce the default padding when a button only has an icon. + padding-left: $grid-unit-10; + padding-right: $grid-unit-10; + min-width: $block-toolbar-height; + justify-content: center; + } + + // @todo: We should extract the tabs styles to the tabs component itself + &.components-tab-button { + font-weight: 500; + + span { + display: inline-block; + padding-left: 0; + padding-right: 0; + position: relative; + } + } + } +} + + +@keyframes components-button__appear-animation { + from { + transform: scaleY(0); + } + to { + transform: scaleY(1); + } } diff --git a/packages/components/src/toolbar/test/index.js b/packages/components/src/toolbar/test/index.js index 748d8a500fc600..d5de14b4a86c57 100644 --- a/packages/components/src/toolbar/test/index.js +++ b/packages/components/src/toolbar/test/index.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { mount } from 'enzyme'; +import { render } from '@testing-library/react'; /** * Internal dependencies @@ -12,51 +12,60 @@ import ToolbarButton from '../../toolbar-button'; describe( 'Toolbar', () => { describe( 'basic rendering', () => { it( 'should render a toolbar with toolbar buttons', () => { - const wrapper = mount( + const { getByLabelText } = render( <Toolbar __experimentalAccessibilityLabel="blocks"> <ToolbarButton label="control1" /> <ToolbarButton label="control2" /> </Toolbar> ); - const control1 = wrapper.find( 'button[aria-label="control1"]' ); - const control2 = wrapper.find( 'button[aria-label="control1"]' ); - expect( control1 ).toHaveLength( 1 ); - expect( control2 ).toHaveLength( 1 ); + + expect( + getByLabelText( 'control1', { selector: 'button' } ) + ).toBeTruthy(); + expect( + getByLabelText( 'control2', { selector: 'button' } ) + ).toBeTruthy(); } ); } ); describe( 'ToolbarGroup', () => { it( 'should render an empty node, when controls are not passed', () => { - const wrapper = mount( <Toolbar /> ); - expect( wrapper.html() ).toBeNull(); + const { container } = render( <Toolbar /> ); + + expect( container.innerHTML ).toBe( '' ); } ); it( 'should render an empty node, when controls are empty', () => { - const wrapper = mount( <Toolbar controls={ [] } /> ); - expect( wrapper.html() ).toBeNull(); + const { container } = render( <Toolbar controls={ [] } /> ); + + expect( container.innerHTML ).toBe( '' ); } ); it( 'should render a list of controls with buttons', () => { - const clickHandler = ( event ) => event; const controls = [ { icon: 'wordpress', title: 'WordPress', subscript: 'wp', - onClick: clickHandler, + onClick: () => {}, isActive: false, }, ]; - const wrapper = mount( <Toolbar controls={ controls } /> ); - const button = wrapper - .find( '[aria-label="WordPress"]' ) - .hostNodes(); - expect( button.props() ).toMatchObject( { - 'aria-label': 'WordPress', - 'aria-pressed': false, - 'data-subscript': 'wp', - type: 'button', - } ); + const { getByLabelText } = render( + <Toolbar controls={ controls } /> + ); + + const toolbarButton = getByLabelText( 'WordPress' ); + expect( toolbarButton.getAttribute( 'aria-label' ) ).toBe( + 'WordPress' + ); + expect( toolbarButton.getAttribute( 'aria-pressed' ) ).toBe( + 'false' + ); + expect( toolbarButton.getAttribute( 'data-subscript' ) ).toBe( + 'wp' + ); + expect( toolbarButton.getAttribute( 'type' ) ).toBe( 'button' ); } ); } ); } ); diff --git a/packages/components/src/toolbar/toolbar-container.js b/packages/components/src/toolbar/toolbar-container.js index d40843ddab3f3f..2ea7cfc7fee8c9 100644 --- a/packages/components/src/toolbar/toolbar-container.js +++ b/packages/components/src/toolbar/toolbar-container.js @@ -15,7 +15,9 @@ import ToolbarContext from '../toolbar-context'; function ToolbarContainer( { accessibilityLabel, ...props }, ref ) { // https://reakit.io/docs/basic-concepts/#state-hooks - const toolbarState = useToolbarState( { loop: true } ); + // Passing baseId for server side rendering (which includes snapshots) + // If an id prop is passed to Toolbar, toolbar items will use it as a base for their ids + const toolbarState = useToolbarState( { loop: true, baseId: props.id } ); return ( // This will provide state for `ToolbarButton`'s diff --git a/packages/components/src/tree-select/stories/index.js b/packages/components/src/tree-select/stories/index.js new file mode 100644 index 00000000000000..c4f299bde2b4cf --- /dev/null +++ b/packages/components/src/tree-select/stories/index.js @@ -0,0 +1,77 @@ +/** + * External dependencies + */ +import { boolean, object, text } from '@storybook/addon-knobs'; + +/** + * WordPress dependencies + */ +import { useState } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import TreeSelect from '../'; + +export default { + title: 'Components/TreeSelect', + component: TreeSelect, +}; + +const TreeSelectWithState = ( props ) => { + const [ selection, setSelection ] = useState(); + + return ( + <TreeSelect + { ...props } + onChange={ setSelection } + selectedId={ selection } + /> + ); +}; + +export const _default = () => { + const label = text( 'Label', 'Label Text' ); + const noOptionLabel = text( 'No Option Label', 'No parent page' ); + const hideLabelFromVision = boolean( 'Hide Label From Vision', false ); + const help = text( + 'Help Text', + 'Help text to explain the select control.' + ); + const tree = object( 'Tree', [ + { + name: 'Page 1', + id: 'p1', + children: [ + { name: 'Descend 1 of page 1', id: 'p11' }, + { name: 'Descend 2 of page 1', id: 'p12' }, + ], + }, + { + name: 'Page 2', + id: 'p2', + children: [ + { + name: 'Descend 1 of page 2', + id: 'p21', + children: [ + { + name: 'Descend 1 of Descend 1 of page 2', + id: 'p211', + }, + ], + }, + ], + }, + ] ); + + return ( + <TreeSelectWithState + label={ label } + noOptionLabel={ noOptionLabel } + hideLabelFromVision={ hideLabelFromVision } + help={ help } + tree={ tree } + /> + ); +}; diff --git a/packages/components/src/unit-control/README.md b/packages/components/src/unit-control/README.md new file mode 100644 index 00000000000000..79100d9cfe4fcb --- /dev/null +++ b/packages/components/src/unit-control/README.md @@ -0,0 +1,37 @@ +# UnitControl + +UnitControl allows the user to set a value as well as a unit (e.g. `px`). + +## Usage + +```jsx +import { __experimentalUnitControl as UnitControl } from '@wordpress/components'; +import { useState } from '@wordpress/element'; + +const Example = () => { + const [value, setValue] = useState(10); + const [unit, setUnit] = useState('px'); + + return ( + <UnitControl + onChange={ setValue } + onUnitChange={ setUnit } + unit={ unit } + value={ value} + /> + ) +}; +``` + +## Props + +Name | Type | Default | Description +--- | --- | --- | --- +`isUnitSelectTabbable` | `boolean` | `true` | Determines if the unit `<select>` is tabbable. +`label` | `string` | | Aria label for the control. +`onChange` | `Function` | `noop` | Callback when the `value` changes. +`onUnitChange` | `Function` | `noop` | Callback when the `unit` changes. +`size` | `string` | `default` | Determines the height of the control. +`unit` | `string` | `px` | Current unit value. +`units` | `Array<string>` | | Collection of available units. +`value` | `number` | | Current number value. \ No newline at end of file diff --git a/packages/components/src/unit-control/index.js b/packages/components/src/unit-control/index.js new file mode 100644 index 00000000000000..7276b10141a55f --- /dev/null +++ b/packages/components/src/unit-control/index.js @@ -0,0 +1,61 @@ +/** + * External dependencies + */ +import { isUndefined, noop } from 'lodash'; +import classnames from 'classnames'; +/** + * Internal dependencies + */ +import { Root, ValueInput } from './styles/unit-control-styles'; +import UnitSelectControl from './unit-select-control'; +import { CSS_UNITS } from './utils'; + +export default function UnitControl( { + className, + isUnitSelectTabbable = true, + isResetValueOnUnitChange = true, + label, + onChange = noop, + onUnitChange = noop, + size = 'default', + style, + unit = 'px', + units = CSS_UNITS, + value, + ...props +} ) { + const handleOnUnitChange = ( unitValue, changeProps ) => { + const { data } = changeProps; + onUnitChange( unitValue, changeProps ); + + if ( isResetValueOnUnitChange && ! isUndefined( data.default ) ) { + onChange( data.default, changeProps ); + } + }; + + const classes = classnames( 'component-unit-control', className ); + + return ( + <Root className={ classes } style={ style }> + <ValueInput + aria-label={ label } + { ...props } + className="component-unit-control__input" + value={ value } + onChange={ onChange } + size={ size } + type="number" + /> + <UnitSelectControl + className="component-unit-control__select" + isTabbable={ isUnitSelectTabbable } + options={ units } + onChange={ handleOnUnitChange } + size={ size } + value={ unit } + /> + </Root> + ); +} + +UnitControl.__defaultUnits = CSS_UNITS; diff --git a/packages/components/src/unit-control/stories/index.js b/packages/components/src/unit-control/stories/index.js new file mode 100644 index 00000000000000..bf5680c6ae630f --- /dev/null +++ b/packages/components/src/unit-control/stories/index.js @@ -0,0 +1,60 @@ +/** + * External dependencies + */ +import { boolean, number, select } from '@storybook/addon-knobs'; +import styled from '@emotion/styled'; + +/** + * WordPress dependencies + */ +import { useState } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import UnitControl from '../'; + +export default { + title: 'Components/UnitControl', + component: UnitControl, +}; + +function Example() { + const [ value, setValue ] = useState( '' ); + const [ unit, setUnit ] = useState( 'px' ); + + const props = { + isShiftStepEnabled: boolean( 'isShiftStepEnabled', true ), + isUnitSelectTabbable: boolean( 'isUnitSelectTabbable', true ), + shiftStep: number( 'shiftStep', 10 ), + size: select( + 'size', + { + default: 'default', + small: 'small', + }, + 'default' + ), + step: number( 'step', 1 ), + }; + + return ( + <ControlWrapperView> + <UnitControl + { ...props } + value={ value } + onChange={ setValue } + unit={ unit } + onUnitChange={ setUnit } + /> + </ControlWrapperView> + ); +} + +export const _default = () => { + return <Example />; +}; + +const ControlWrapperView = styled.div` + max-width: 80px; +`; diff --git a/packages/components/src/unit-control/styles/unit-control-styles.js b/packages/components/src/unit-control/styles/unit-control-styles.js new file mode 100644 index 00000000000000..eb17bdf1d87fb8 --- /dev/null +++ b/packages/components/src/unit-control/styles/unit-control-styles.js @@ -0,0 +1,153 @@ +/** + * External dependencies + */ +import { css } from '@emotion/core'; +import styled from '@emotion/styled'; +/** + * Internal dependencies + */ +import { color, rtl } from '../../utils/style-mixins'; +import NumberControl from '../../number-control'; + +export const Root = styled.div` + box-sizing: border-box; + position: relative; +`; + +const fontSizeStyles = ( { size } ) => { + const sizes = { + default: null, + small: '11px', + }; + + const fontSize = sizes[ size ]; + + if ( ! fontSize ) return ''; + + return css` + @media ( min-width: 600px ) { + font-size: ${fontSize}; + } + `; +}; + +const sizeStyles = ( { size } ) => { + const sizes = { + default: { + height: 30, + lineHeight: 30, + minHeight: 30, + }, + small: { + height: 24, + lineHeight: 24, + minHeight: 24, + }, + }; + + const style = sizes[ size ] || sizes.default; + + return css( style ); +}; + +// TODO: Resolve need to use &&& to increase specificity +// https://github.com/WordPress/gutenberg/issues/18483 + +export const ValueInput = styled( NumberControl )` + &&& { + appearance: none; + -moz-appearance: textfield; + box-sizing: border-box; + border: 1px solid ${color( 'ui.border' )}; + border-radius: 2px; + padding: 3px 8px; + display: block; + width: 100%; + + &::-webkit-outer-spin-button, + &::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; + } + + ${rtl( { paddingRight: 20 } )} + ${fontSizeStyles}; + ${sizeStyles}; + } +`; + +const unitSizeStyles = ( { size } ) => { + const sizes = { + default: { + top: 5, + height: 20, + minHeight: 20, + }, + small: { + top: 4, + height: 16, + minHeight: 16, + }, + }; + + return css( sizes[ size ] ); +}; + +const baseUnitLabelStyles = ( props ) => { + return css` + appearance: none; + background: ${color( 'ui.background' )}; + border-radius: 2px; + border: none; + box-sizing: border-box; + color: ${color( 'darkGray.500' )}; + display: block; + font-size: 8px; + line-height: 1; + letter-spacing: -0.5px; + outline: none; + padding: 2px 2px; + position: absolute; + text-align-last: center; + text-transform: uppercase; + width: 22px; + z-index: 1; + + ${rtl( { right: 4 } )()} + ${unitSizeStyles( props )} + `; +}; + +const unitLabelPaddingStyles = ( { size } ) => { + const sizes = { + default: '6px 2px', + small: '4px 2px', + }; + + return css( { padding: sizes[ size ] } ); +}; + +export const UnitLabel = styled.div` + &&& { + ${baseUnitLabelStyles}; + ${unitLabelPaddingStyles}; + } +`; + +export const UnitSelect = styled.select` + &&& { + ${baseUnitLabelStyles}; + cursor: pointer; + border: 1px solid transparent; + + &:hover { + background-color: ${color( 'lightGray.300' )}; + } + + &:focus { + border-color: ${color( 'ui.borderFocus' )}; + outline: 2px solid transparent; + outline-offset: 0; + } + } +`; diff --git a/packages/components/src/unit-control/test/index.js b/packages/components/src/unit-control/test/index.js new file mode 100644 index 00000000000000..32bad94884076d --- /dev/null +++ b/packages/components/src/unit-control/test/index.js @@ -0,0 +1,283 @@ +/** + * External dependencies + */ +import { render, unmountComponentAtNode } from 'react-dom'; +import { act, Simulate } from 'react-dom/test-utils'; + +/** + * WordPress dependencies + */ +import { UP, DOWN } from '@wordpress/keycodes'; + +/** + * Internal dependencies + */ +import UnitControl from '../'; + +let container = null; + +beforeEach( () => { + container = document.createElement( 'div' ); + document.body.appendChild( container ); +} ); + +afterEach( () => { + unmountComponentAtNode( container ); + container.remove(); + container = null; +} ); + +const getComponent = () => container.querySelector( '.component-unit-control' ); +const getInput = () => + container.querySelector( '.component-unit-control__input' ); +const getSelect = () => + container.querySelector( '.component-unit-control__select' ); + +describe( 'UnitControl', () => { + describe( 'Basic rendering', () => { + it( 'should render', () => { + act( () => { + render( <UnitControl />, container ); + } ); + const input = getInput(); + const select = getSelect(); + + expect( input ).toBeTruthy(); + expect( select ).toBeTruthy(); + } ); + + it( 'should render custom className', () => { + act( () => { + render( <UnitControl className="hello" />, container ); + } ); + + const el = getComponent(); + + expect( el.classList.contains( 'hello' ) ).toBe( true ); + } ); + + it( 'should not render select, if units are disabled', () => { + act( () => { + render( <UnitControl unit="em" units={ false } />, container ); + } ); + const input = getInput(); + const select = getSelect(); + + expect( input ).toBeTruthy(); + expect( select ).toBeFalsy(); + } ); + } ); + + describe( 'Value', () => { + it( 'should update value on change', () => { + let state = 50; + const setState = ( nextState ) => ( state = nextState ); + + act( () => { + render( + <UnitControl value={ state } onChange={ setState } />, + container + ); + } ); + + const input = getInput(); + + act( () => { + Simulate.change( input, { target: { value: 62 } } ); + } ); + + expect( state ).toBe( 62 ); + } ); + + it( 'should increment value on UP press', () => { + let state = 50; + const setState = ( nextState ) => ( state = nextState ); + + act( () => { + render( + <UnitControl value={ state } onChange={ setState } />, + container + ); + } ); + + const input = getInput(); + + act( () => { + Simulate.keyDown( input, { keyCode: UP } ); + } ); + + expect( state ).toBe( '51' ); + } ); + + it( 'should increment value on UP + SHIFT press, with step', () => { + let state = 50; + const setState = ( nextState ) => ( state = nextState ); + + act( () => { + render( + <UnitControl value={ state } onChange={ setState } />, + container + ); + } ); + + const input = getInput(); + + act( () => { + Simulate.keyDown( input, { keyCode: UP, shiftKey: true } ); + } ); + + expect( state ).toBe( '60' ); + } ); + + it( 'should decrement value on DOWN press', () => { + let state = 50; + const setState = ( nextState ) => ( state = nextState ); + + act( () => { + render( + <UnitControl value={ state } onChange={ setState } />, + container + ); + } ); + + const input = getInput(); + + act( () => { + Simulate.keyDown( input, { keyCode: DOWN } ); + } ); + + expect( state ).toBe( '49' ); + } ); + + it( 'should decrement value on DOWN + SHIFT press, with step', () => { + let state = 50; + const setState = ( nextState ) => ( state = nextState ); + + act( () => { + render( + <UnitControl value={ state } onChange={ setState } />, + container + ); + } ); + + const input = getInput(); + + act( () => { + Simulate.keyDown( input, { keyCode: DOWN, shiftKey: true } ); + } ); + + expect( state ).toBe( '40' ); + } ); + } ); + + describe( 'Unit', () => { + it( 'should update unit value on change', () => { + let state = 'px'; + const setState = ( nextState ) => ( state = nextState ); + + act( () => { + render( + <UnitControl unit={ state } onUnitChange={ setState } />, + container + ); + } ); + + const select = getSelect(); + + act( () => { + Simulate.change( select, { target: { value: 'em' } } ); + } ); + + expect( state ).toBe( 'em' ); + } ); + + it( 'should render customized units, if defined', () => { + const units = [ + { value: 'pt', label: 'pt', default: 0 }, + { value: 'vmax', label: 'vmax', default: 10 }, + ]; + act( () => { + render( <UnitControl units={ units } />, container ); + } ); + + const select = getSelect(); + const options = select.querySelectorAll( 'option' ); + + expect( options.length ).toBe( 2 ); + + const [ pt, vmax ] = options; + + expect( pt.value ).toBe( 'pt' ); + expect( vmax.value ).toBe( 'vmax' ); + } ); + + it( 'should reset value on unit change, if unit has default value', () => { + let state = 50; + const setState = ( nextState ) => ( state = nextState ); + + const units = [ + { value: 'pt', label: 'pt', default: 25 }, + { value: 'vmax', label: 'vmax', default: 75 }, + ]; + act( () => { + render( + <UnitControl + units={ units } + onChange={ setState } + value={ state } + />, + container + ); + } ); + + const select = getSelect(); + + act( () => { + Simulate.change( select, { target: { value: 'vmax' } } ); + } ); + + expect( state ).toBe( 75 ); + + act( () => { + Simulate.change( select, { target: { value: 'pt' } } ); + } ); + + expect( state ).toBe( 25 ); + } ); + + it( 'should not reset value on unit change, if disabled', () => { + let state = 50; + const setState = ( nextState ) => ( state = nextState ); + + const units = [ + { value: 'pt', label: 'pt', default: 25 }, + { value: 'vmax', label: 'vmax', default: 75 }, + ]; + act( () => { + render( + <UnitControl + isResetValueOnUnitChange={ false } + value={ state } + units={ units } + onChange={ setState } + />, + container + ); + } ); + + const select = getSelect(); + + act( () => { + Simulate.change( select, { target: { value: 'vmax' } } ); + } ); + + expect( state ).toBe( 50 ); + + act( () => { + Simulate.change( select, { target: { value: 'pt' } } ); + } ); + + expect( state ).toBe( 50 ); + } ); + } ); +} ); diff --git a/packages/components/src/unit-control/unit-select-control.js b/packages/components/src/unit-control/unit-select-control.js new file mode 100644 index 00000000000000..6844b5c959963a --- /dev/null +++ b/packages/components/src/unit-control/unit-select-control.js @@ -0,0 +1,55 @@ +/** + * External dependencies + */ +import { noop, isEmpty } from 'lodash'; +import classnames from 'classnames'; + +/** + * Internal dependencies + */ +import { UnitSelect, UnitLabel } from './styles/unit-control-styles'; +import { CSS_UNITS } from './utils'; + +/** + * Renders a `select` if there are multiple units. + * Otherwise, renders a non-selectable label. + */ +export default function UnitSelectControl( { + className, + isTabbable = true, + options = CSS_UNITS, + onChange = noop, + size = 'default', + value = 'px', + ...props +} ) { + if ( isEmpty( options ) || options.length === 1 || options === false ) { + return <UnitLabel size={ size }>{ value }</UnitLabel>; + } + + const handleOnChange = ( event ) => { + const { value: unitValue } = event.target; + const data = options.find( ( option ) => option.value === unitValue ); + + onChange( unitValue, { event, data } ); + }; + + const classes = classnames( 'component-unit-control__select', className ); + + return ( + <UnitSelect + className={ classes } + onChange={ handleOnChange } + size={ size } + tabIndex={ isTabbable ? null : '-1' } + value={ value } + { ...props } + > + { options.map( ( option ) => ( + <option value={ option.value } key={ option.value }> + { option.label } + </option> + ) ) } + </UnitSelect> + ); +} diff --git a/packages/components/src/unit-control/utils.js b/packages/components/src/unit-control/utils.js new file mode 100644 index 00000000000000..aa886479f27d2a --- /dev/null +++ b/packages/components/src/unit-control/utils.js @@ -0,0 +1,8 @@ +export const CSS_UNITS = [ + { value: 'px', label: 'px', default: 0 }, + { value: '%', label: '%', default: 10 }, + { value: 'em', label: 'em', default: 0 }, + { value: 'rem', label: 'rem', default: 0 }, + { value: 'vw', label: 'vw', default: 10 }, + { value: 'vh', label: 'vh', default: 10 }, +]; diff --git a/packages/components/src/utils/colors-values.js b/packages/components/src/utils/colors-values.js index 537a8e7810300b..7e152a4263cc8f 100644 --- a/packages/components/src/utils/colors-values.js +++ b/packages/components/src/utils/colors-values.js @@ -1,12 +1,44 @@ +/** + * External dependencies + */ +import { merge } from 'lodash'; + /** * Internal dependencies */ import { rgba } from './colors'; + export const BASE = { black: '#000', white: '#fff', }; +/** + * TODO: Continue to update values as "G2" design evolves. + * + * "G2" refers to the movement to advance the interface of the block editor. + * https://github.com/WordPress/gutenberg/issues/18667 + */ +export const G2 = { + blue: { + medium: { + focus: '#007cba', + focusDark: '#fff', + }, + }, + darkGray: { + primary: '#1e1e1e', + }, + mediumGray: { + text: '#757575', + }, + lightGray: { + ui: '#949494', + secondary: '#ccc', + tertiary: '#e7e8e9', + }, +}; + export const DARK_GRAY = { 900: '#191e23', 800: '#23282d', @@ -101,15 +133,24 @@ export const ALERT = { green: '#4ab866', }; +// Namespaced values for raw colors hex codes +export const UI = { + background: BASE.white, + border: BASE.black, + borderFocus: BLUE.medium.focus, +}; + export const COLORS = { ...BASE, - darkGray: DARK_GRAY, + darkGray: merge( {}, DARK_GRAY, G2.darkGray ), darkOpacity: DARK_OPACITY, darkOpacityLight: DARK_OPACITY_LIGHT, - lightGray: LIGHT_GRAY, + mediumGray: G2.mediumGray, + lightGray: merge( {}, LIGHT_GRAY, G2.lightGray ), lightGrayLight: LIGHT_OPACITY_LIGHT, - blue: BLUE, + blue: merge( {}, BLUE, G2.blue ), alert: ALERT, + ui: UI, }; export default COLORS; diff --git a/packages/components/src/utils/reduce-motion.js b/packages/components/src/utils/reduce-motion.js index b3651d494c66eb..16b79b37944309 100644 --- a/packages/components/src/utils/reduce-motion.js +++ b/packages/components/src/utils/reduce-motion.js @@ -2,7 +2,7 @@ * Allows users to opt-out of animations via OS-level preferences. * * @param {string} prop CSS Property name - * @return {string} + * @return {string} Generated CSS code for the reduced style */ export function reduceMotion( prop = 'transition' ) { let style; diff --git a/packages/compose/package.json b/packages/compose/package.json index 98b445f213cb72..105f18e00cb547 100644 --- a/packages/compose/package.json +++ b/packages/compose/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/compose", - "version": "3.11.0", + "version": "3.13.1", "description": "WordPress higher-order components (HOCs).", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -23,7 +23,7 @@ "react-native": "src/index", "sideEffects": false, "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/element": "file:../element", "@wordpress/is-shallow-equal": "file:../is-shallow-equal", "lodash": "^4.17.15", diff --git a/packages/compose/src/hooks/use-media-query/index.js b/packages/compose/src/hooks/use-media-query/index.js index e863503ba940bc..63168c218a6e5f 100644 --- a/packages/compose/src/hooks/use-media-query/index.js +++ b/packages/compose/src/hooks/use-media-query/index.js @@ -10,7 +10,10 @@ import { useState, useEffect } from '@wordpress/element'; * @return {boolean} return value of the media query. */ export default function useMediaQuery( query ) { - const [ match, setMatch ] = useState( false ); + const [ match, setMatch ] = useState( + query && window.matchMedia( query ).matches + ); + useEffect( () => { if ( ! query ) { return; diff --git a/packages/compose/src/hooks/use-media-query/test/index.js b/packages/compose/src/hooks/use-media-query/test/index.js index a256a4b440bec4..b6145debdfc6ca 100644 --- a/packages/compose/src/hooks/use-media-query/test/index.js +++ b/packages/compose/src/hooks/use-media-query/test/index.js @@ -33,6 +33,18 @@ describe( 'useMediaQuery', () => { return `useMediaQuery: ${ queryResult }`; }; + it( 'should return true when query matches on the first render', async () => { + global.matchMedia.mockReturnValue( { + addListener, + removeListener, + matches: true, + } ); + + const root = create( <TestComponent query="(min-width: 782px)" /> ); + + expect( root.toJSON() ).toBe( 'useMediaQuery: true' ); + } ); + it( 'should return true when query matches', async () => { global.matchMedia.mockReturnValue( { addListener, @@ -55,6 +67,13 @@ describe( 'useMediaQuery', () => { } ); it( 'should correctly update the value when the query evaluation matches', async () => { + // first render + global.matchMedia.mockReturnValueOnce( { + addListener, + removeListener, + matches: true, + } ); + // the query within useEffect global.matchMedia.mockReturnValueOnce( { addListener, removeListener, diff --git a/packages/core-data/README.md b/packages/core-data/README.md index a2bb3ccbe6deeb..5e2d337eabea42 100644 --- a/packages/core-data/README.md +++ b/packages/core-data/README.md @@ -40,7 +40,7 @@ const MyAuthorsList = withSelect( ( select ) => ( { The following set of dispatching action creators are available on the object returned by `wp.data.dispatch( 'core' )`: -<!-- START TOKEN(Autogenerated actions) --> +<!-- START TOKEN(Autogenerated actions|src/actions.js) --> <a name="addEntities" href="#addEntities">#</a> **addEntities** @@ -86,6 +86,18 @@ _Returns_ - `Object`: Action object. +<a name="receiveCurrentTheme" href="#receiveCurrentTheme">#</a> **receiveCurrentTheme** + +Returns an action object used in signalling that the current theme has been received. + +_Parameters_ + +- _currentTheme_ `Object`: The current theme. + +_Returns_ + +- `Object`: Action object. + <a name="receiveCurrentUser" href="#receiveCurrentUser">#</a> **receiveCurrentUser** Returns an action used in signalling that the current user has been received. @@ -211,13 +223,13 @@ _Parameters_ Action triggered to undo the last edit to an entity record, if any. -<!-- END TOKEN(Autogenerated actions) --> +<!-- END TOKEN(Autogenerated actions|src/actions.js) --> ## Selectors The following selectors are available on the object returned by `wp.data.select( 'core' )`: -<!-- START TOKEN(Autogenerated selectors) --> +<!-- START TOKEN(Autogenerated selectors|src/selectors.js) --> <a name="canUser" href="#canUser">#</a> **canUser** @@ -284,6 +296,18 @@ _Returns_ - `?Array`: An array of autosaves for the post, or undefined if there is none. +<a name="getCurrentTheme" href="#getCurrentTheme">#</a> **getCurrentTheme** + +Return the current theme. + +_Parameters_ + +- _state_ `Object`: Data state. + +_Returns_ + +- `Object`: The current theme. + <a name="getCurrentUser" href="#getCurrentUser">#</a> **getCurrentUser** Returns the current user. @@ -413,7 +437,7 @@ _Parameters_ _Returns_ -- `Array`: Records. +- `?Array`: Records. <a name="getLastEntitySaveError" href="#getLastEntitySaveError">#</a> **getLastEntitySaveError** @@ -655,6 +679,6 @@ _Returns_ - `boolean`: Whether the entity record is saving or not. -<!-- END TOKEN(Autogenerated selectors) --> +<!-- END TOKEN(Autogenerated selectors|src/selectors.js) --> <br/><br/><p align="center"><img src="https://s.w.org/style/images/codeispoetry.png?1" alt="Code is Poetry." /></p> diff --git a/packages/core-data/package.json b/packages/core-data/package.json index 6f303ba4849b39..febff43a5c2533 100644 --- a/packages/core-data/package.json +++ b/packages/core-data/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/core-data", - "version": "2.12.1", + "version": "2.14.1", "description": "Access to and manipulation of core WordPress entities.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -22,10 +22,11 @@ "module": "build-module/index.js", "react-native": "src/index", "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/api-fetch": "file:../api-fetch", "@wordpress/blocks": "file:../blocks", "@wordpress/data": "file:../data", + "@wordpress/data-controls": "file:../data-controls", "@wordpress/deprecated": "file:../deprecated", "@wordpress/element": "file:../element", "@wordpress/i18n": "file:../i18n", diff --git a/packages/core-data/src/actions.js b/packages/core-data/src/actions.js index dd4b10c3e2fda6..8a3de939904ce3 100644 --- a/packages/core-data/src/actions.js +++ b/packages/core-data/src/actions.js @@ -94,6 +94,20 @@ export function receiveEntityRecords( }; } +/** + * Returns an action object used in signalling that the current theme has been received. + * + * @param {Object} currentTheme The current theme. + * + * @return {Object} Action object. + */ +export function receiveCurrentTheme( currentTheme ) { + return { + type: 'RECEIVE_CURRENT_THEME', + currentTheme, + }; +} + /** * Returns an action object used in signalling that the index has been received. * diff --git a/packages/core-data/src/entities.js b/packages/core-data/src/entities.js index 2e8ae68a88dd41..8a9fa25ce3c648 100644 --- a/packages/core-data/src/entities.js +++ b/packages/core-data/src/entities.js @@ -22,6 +22,9 @@ export const defaultEntities = [ name: 'site', kind: 'root', baseURL: '/wp/v2/settings', + getTitle: ( record ) => { + return get( record, [ 'title' ], __( 'Site Title' ) ); + }, }, { label: __( 'Post Type' ), @@ -67,6 +70,27 @@ export const defaultEntities = [ plural: 'comments', label: __( 'Comment' ), }, + { + name: 'menu', + kind: 'root', + baseURL: '/__experimental/menus', + plural: 'menus', + label: __( 'Menu' ), + }, + { + name: 'menuItem', + kind: 'root', + baseURL: '/__experimental/menu-items', + plural: 'menuItems', + label: __( 'Menu Item' ), + }, + { + name: 'menuLocation', + kind: 'root', + baseURL: '/__experimental/menu-locations', + plural: 'menuLocations', + label: __( 'Menu Location' ), + }, ]; export const kinds = [ diff --git a/packages/core-data/src/reducer.js b/packages/core-data/src/reducer.js index 932ae2959a0476..b324010b787fe2 100644 --- a/packages/core-data/src/reducer.js +++ b/packages/core-data/src/reducer.js @@ -102,6 +102,43 @@ export function taxonomies( state = [], action ) { return state; } +/** + * Reducer managing the current theme. + * + * @param {string} state Current state. + * @param {Object} action Dispatched action. + * + * @return {string} Updated state. + */ +export function currentTheme( state = undefined, action ) { + switch ( action.type ) { + case 'RECEIVE_CURRENT_THEME': + return action.currentTheme.stylesheet; + } + + return state; +} + +/** + * Reducer managing installed themes. + * + * @param {Object} state Current state. + * @param {Object} action Dispatched action. + * + * @return {Object} Updated state. + */ +export function themes( state = {}, action ) { + switch ( action.type ) { + case 'RECEIVE_CURRENT_THEME': + return { + ...state, + [ action.currentTheme.stylesheet ]: action.currentTheme, + }; + } + + return state; +} + /** * Reducer managing theme supports data. * @@ -502,8 +539,10 @@ export function autosaves( state = {}, action ) { export default combineReducers( { terms, users, + currentTheme, currentUser, taxonomies, + themes, themeSupports, entities, undo, diff --git a/packages/core-data/src/resolvers.js b/packages/core-data/src/resolvers.js index b492a63e67e99e..a1c8ddaf33f63e 100644 --- a/packages/core-data/src/resolvers.js +++ b/packages/core-data/src/resolvers.js @@ -14,6 +14,7 @@ import deprecated from '@wordpress/deprecated'; */ import { receiveUserQuery, + receiveCurrentTheme, receiveCurrentUser, receiveEntityRecords, receiveThemeSupports, @@ -23,6 +24,7 @@ import { } from './actions'; import { getKindEntities } from './entities'; import { apiFetch, resolveSelect } from './controls'; +import { ifNotResolved } from './utils'; /** * Requests authors from the REST API. @@ -61,6 +63,22 @@ export function* getEntityRecord( kind, name, key = '' ) { yield receiveEntityRecords( kind, name, record ); } +/** + * Requests an entity's record from the REST API. + */ +export const getRawEntityRecord = ifNotResolved( + getEntityRecord, + 'getEntityRecord' +); + +/** + * Requests an entity's record from the REST API. + */ +export const getEditedEntityRecord = ifNotResolved( + getRawEntityRecord, + 'getRawEntityRecord' +); + /** * Requests the entity's records from the REST API. * @@ -91,6 +109,16 @@ getEntityRecords.shouldInvalidate = ( action, kind, name ) => { ); }; +/** + * Requests the current theme. + */ +export function* getCurrentTheme() { + const activeThemes = yield apiFetch( { + path: '/wp/v2/themes?status=active', + } ); + yield receiveCurrentTheme( activeThemes[ 0 ] ); +} + /** * Requests theme supports data from the index. */ diff --git a/packages/core-data/src/selectors.js b/packages/core-data/src/selectors.js index 94c09522f86313..815ff190315478 100644 --- a/packages/core-data/src/selectors.js +++ b/packages/core-data/src/selectors.js @@ -179,7 +179,7 @@ export const getRawEntityRecord = createSelector( * @param {string} name Entity name. * @param {?Object} query Optional terms query. * - * @return {Array} Records. + * @return {?Array} Records. */ export function getEntityRecords( state, kind, name, query ) { const queriedState = get( state.entities.data, [ @@ -449,6 +449,17 @@ export function hasRedo( state ) { return Boolean( getRedoEdit( state ) ); } +/** + * Return the current theme. + * + * @param {Object} state Data state. + * + * @return {Object} The current theme. + */ +export function getCurrentTheme( state ) { + return state.themes[ state.currentTheme ]; +} + /** * Return theme supports data in the index. * diff --git a/packages/core-data/src/utils/if-not-resolved.js b/packages/core-data/src/utils/if-not-resolved.js new file mode 100644 index 00000000000000..2b3c25427f63f8 --- /dev/null +++ b/packages/core-data/src/utils/if-not-resolved.js @@ -0,0 +1,35 @@ +/** + * WordPress dependencies + */ +import { select } from '@wordpress/data-controls'; + +/** + * Higher-order function which invokes the given resolver only if it has not + * already been resolved with the arguments passed to the enhanced function. + * + * This only considers resolution state, and notably does not support resolver + * custom `isFulfilled` behavior. + * + * @param {Function} resolver Original resolver. + * @param {string} selectorName Selector name associated with resolver. + * + * @return {Function} Enhanced resolver. + */ +const ifNotResolved = ( resolver, selectorName ) => + /** + * @param {...any} args Original resolver arguments. + */ + function* resolveIfNotResolved( ...args ) { + const hasStartedResolution = yield select( + 'core', + 'hasStartedResolution', + selectorName, + args + ); + + if ( ! hasStartedResolution ) { + yield* resolver( ...args ); + } + }; + +export default ifNotResolved; diff --git a/packages/core-data/src/utils/index.js b/packages/core-data/src/utils/index.js index 7adb57e48d5d7f..8605593479a65d 100644 --- a/packages/core-data/src/utils/index.js +++ b/packages/core-data/src/utils/index.js @@ -1,5 +1,6 @@ export { default as conservativeMapItem } from './conservative-map-item'; export { default as ifMatchingAction } from './if-matching-action'; +export { default as ifNotResolved } from './if-not-resolved'; export { default as onSubKey } from './on-sub-key'; export { default as replaceAction } from './replace-action'; export { default as withWeakMapCache } from './with-weak-map-cache'; diff --git a/packages/core-data/src/utils/test/if-not-resolved.js b/packages/core-data/src/utils/test/if-not-resolved.js new file mode 100644 index 00000000000000..ff960687539fae --- /dev/null +++ b/packages/core-data/src/utils/test/if-not-resolved.js @@ -0,0 +1,69 @@ +/** + * WordPress dependencies + */ +import { select } from '@wordpress/data-controls'; + +/** + * Internal dependencies + */ +import ifNotResolved from '../if-not-resolved'; + +jest.mock( '@wordpress/data-controls', () => ( { + select: jest.fn(), +} ) ); + +describe( 'ifNotResolved', () => { + beforeEach( () => { + select.mockReset(); + } ); + + it( 'returns a new function', () => { + const originalResolver = () => {}; + + const resolver = ifNotResolved( originalResolver, 'originalResolver' ); + + expect( resolver ).toBeInstanceOf( Function ); + } ); + + it( 'triggers original resolver if not already resolved', () => { + select.mockImplementation( ( _storeKey, selectorName ) => ( { + _nextValue: + selectorName === 'hasStartedResolution' ? false : undefined, + } ) ); + + const originalResolver = jest.fn().mockImplementation( function*() {} ); + + const resolver = ifNotResolved( originalResolver, 'originalResolver' ); + + const runResolver = resolver(); + + let next, nextValue; + do { + next = runResolver.next( nextValue ); + nextValue = next.value?._nextValue; + } while ( ! next.done ); + + expect( originalResolver ).toHaveBeenCalledTimes( 1 ); + } ); + + it( 'does not trigger original resolver if already resolved', () => { + select.mockImplementation( ( _storeKey, selectorName ) => ( { + _nextValue: + selectorName === 'hasStartedResolution' ? true : undefined, + } ) ); + + const originalResolver = jest.fn().mockImplementation( function*() {} ); + + const resolver = ifNotResolved( originalResolver, 'originalResolver' ); + + const runResolver = resolver(); + + let next, nextValue; + do { + next = runResolver.next( nextValue ); + nextValue = next.value?._nextValue; + } while ( ! next.done ); + + expect( originalResolver ).toHaveBeenCalledTimes( 0 ); + } ); +} ); diff --git a/packages/create-block/CHANGELOG.md b/packages/create-block/CHANGELOG.md index 2adea266a25d4f..935db8124f3fd0 100644 --- a/packages/create-block/CHANGELOG.md +++ b/packages/create-block/CHANGELOG.md @@ -1,5 +1,7 @@ ## Master +## 0.10.0 (2020-04-01) + ### New Features - Added readme.txt file to the existing templates to make your entry in the plugin browser most useful ([#20694](https://github.com/WordPress/gutenberg/pull/20694)). diff --git a/packages/create-block/package.json b/packages/create-block/package.json index 295c4dd53592fa..7d39d685f51d41 100644 --- a/packages/create-block/package.json +++ b/packages/create-block/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/create-block", - "version": "0.9.0", + "version": "0.11.0", "description": "Generates PHP, JS and CSS code for registering a block for a WordPress plugin.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -30,11 +30,11 @@ "wp-create-block": "./index.js" }, "dependencies": { - "chalk": "^2.4.2", + "chalk": "^4.0.0", "check-node-version": "^3.1.1", "commander": "^4.1.0", "execa": "^4.0.0", - "inquirer": "^7.0.3", + "inquirer": "^7.1.0", "lodash": "^4.17.15", "make-dir": "^3.0.0", "mustache": "^4.0.0", diff --git a/packages/data-controls/package.json b/packages/data-controls/package.json index dfded291988246..9ecb33e1385683 100644 --- a/packages/data-controls/package.json +++ b/packages/data-controls/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/data-controls", - "version": "1.8.1", + "version": "1.10.1", "description": "A set of common controls for the @wordpress/data api.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/data/README.md b/packages/data/README.md index 5e53e5c406f5c4..fc904d64e3a861 100644 --- a/packages/data/README.md +++ b/packages/data/README.md @@ -100,20 +100,20 @@ registerStore( 'my-shop', { } ); ``` -The return value of `registerStore` is a [Redux-like store object](https://redux.js.org/docs/basics/Store.html) with the following methods: +The return value of `registerStore` is a [Redux-like store object](https://redux.js.org/basics/store) with the following methods: - `store.getState()`: Returns the state value of the registered reducer - - _Redux parallel:_ [`getState`](https://redux.js.org/api-reference/store#getState) + - _Redux parallel:_ [`getState`](https://redux.js.org/api/store#getstate) - `store.subscribe( listener: Function )`: Registers a function called any time the value of state changes. - - _Redux parallel:_ [`subscribe`](https://redux.js.org/api-reference/store#subscribe(listener)) + - _Redux parallel:_ [`subscribe`](https://redux.js.org/api/store#subscribelistener) - `store.dispatch( action: Object )`: Given an action object, calls the registered reducer and updates the state value. - - _Redux parallel:_ [`dispatch`](https://redux.js.org/api-reference/store#dispatch(action)) + - _Redux parallel:_ [`dispatch`](https://redux.js.org/api/store#dispatchaction) ### Options #### `reducer` -A [**reducer**](https://redux.js.org/docs/basics/Reducers.html) is a function accepting the previous `state` and `action` as arguments and returns an updated `state` value. +A [**reducer**](https://redux.js.org/basics/reducers) is a function accepting the previous `state` and `action` as arguments and returns an updated `state` value. #### `actions` @@ -148,7 +148,7 @@ The `@wordpress/data` module offers a more advanced and generic interface for th - `getSelectors()`: Returns an object of selector functions, pre-mapped to the store. - `getActions()`: Returns an object of action functions, pre-mapped to the store. - `subscribe( listener: Function )`: Registers a function called any time the value of state changes. - - Behaves as Redux [`subscribe`](https://redux.js.org/api-reference/store#subscribe(listener)) + - Behaves as Redux [`subscribe`](https://redux.js.org/api/store#subscribelistener) with the following differences: - Doesn't have to implement an unsubscribe, since the registry never uses it. \- Only has to support one listener (the registry). diff --git a/packages/data/package.json b/packages/data/package.json index d23950462b3ca7..472a699e95bba2 100644 --- a/packages/data/package.json +++ b/packages/data/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/data", - "version": "4.14.1", + "version": "4.16.1", "description": "Data module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -22,7 +22,7 @@ "module": "build-module/index.js", "react-native": "src/index", "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/compose": "file:../compose", "@wordpress/deprecated": "file:../deprecated", "@wordpress/element": "file:../element", @@ -32,7 +32,7 @@ "equivalent-key-map": "^0.2.2", "is-promise": "^2.1.0", "lodash": "^4.17.15", - "memize": "^1.0.5", + "memize": "^1.1.0", "redux": "^4.0.0", "turbo-combine-reducers": "^1.0.2", "use-memo-one": "^1.1.1" diff --git a/packages/data/src/namespace-store/test/index.js b/packages/data/src/namespace-store/test/index.js index 5f0eb4cb792d39..915b9bbfe65e8e 100644 --- a/packages/data/src/namespace-store/test/index.js +++ b/packages/data/src/namespace-store/test/index.js @@ -42,7 +42,7 @@ describe( 'controls', () => { } ); } ); - it( 'resolves in expected order', ( done ) => { + it( 'resolves in expected order', async () => { const actions = { wait: () => ( { type: 'WAIT' } ), receive: ( items ) => ( { type: 'RECEIVE', items } ), @@ -74,21 +74,23 @@ describe( 'controls', () => { }, } ); - registry.subscribe( () => { - const isFinished = registry - .select( 'store' ) - .hasFinishedResolution( 'getItems' ); - if ( isFinished ) { - expect( registry.select( 'store' ).getItems() ).toEqual( [ - 1, - 2, - 3, - ] ); - done(); - } - } ); + return new Promise( ( resolve ) => { + registry.subscribe( () => { + const isFinished = registry + .select( 'store' ) + .hasFinishedResolution( 'getItems' ); + if ( isFinished ) { + expect( registry.select( 'store' ).getItems() ).toEqual( [ + 1, + 2, + 3, + ] ); + } + resolve(); + } ); - registry.select( 'store' ).getItems(); + registry.select( 'store' ).getItems(); + } ); } ); describe( 'selectors have expected value for the `hasResolver` property', () => { it( 'when custom store has resolvers defined', () => { diff --git a/packages/data/src/plugins/persistence/index.js b/packages/data/src/plugins/persistence/index.js index 30ac60abbc3cc7..75fe54a394efed 100644 --- a/packages/data/src/plugins/persistence/index.js +++ b/packages/data/src/plugins/persistence/index.js @@ -246,6 +246,26 @@ persistencePlugin.__unstableMigrate = ( pluginOptions ) => { } ); } + let editPostState = state[ 'core/edit-post' ]; + + // Default `fullscreenMode` to `false` if any persisted state had existed + // and the user hadn't made an explicit choice about fullscreen mode. This + // is needed since `fullscreenMode` previously did not have a default value + // and was implicitly false by its absence. It is now `true` by default, but + // this change is not intended to affect upgrades from earlier versions. + const hadPersistedState = Object.keys( state ).length > 0; + const hadFullscreenModePreference = has( state, [ + 'core/edit-post', + 'preferences', + 'features', + 'fullscreenMode', + ] ); + if ( hadPersistedState && ! hadFullscreenModePreference ) { + editPostState = merge( {}, editPostState, { + preferences: { features: { fullscreenMode: false } }, + } ); + } + // Migrate 'areTipsEnabled' from 'core/nux' to 'showWelcomeGuide' in 'core/edit-post' const areTipsEnabled = get( state, [ 'core/nux', @@ -259,16 +279,17 @@ persistencePlugin.__unstableMigrate = ( pluginOptions ) => { 'welcomeGuide', ] ); if ( areTipsEnabled !== undefined && ! hasWelcomeGuide ) { - persistence.set( - 'core/edit-post', - merge( state[ 'core/edit-post' ], { - preferences: { - features: { - welcomeGuide: areTipsEnabled, - }, + editPostState = merge( {}, editPostState, { + preferences: { + features: { + welcomeGuide: areTipsEnabled, }, - } ) - ); + }, + } ); + } + + if ( editPostState !== state[ 'core/edit-post' ] ) { + persistence.set( 'core/edit-post', editPostState ); } }; diff --git a/packages/data/src/plugins/persistence/test/index.js b/packages/data/src/plugins/persistence/test/index.js index 4d91648ce81da3..818f075640ae56 100644 --- a/packages/data/src/plugins/persistence/test/index.js +++ b/packages/data/src/plugins/persistence/test/index.js @@ -11,7 +11,7 @@ import objectStorage from '../storage/object'; import { createRegistry } from '../../../'; describe( 'persistence', () => { - let registry, originalRegisterStore; + let registry; beforeAll( () => { jest.spyOn( objectStorage, 'setItem' ); @@ -21,18 +21,8 @@ describe( 'persistence', () => { objectStorage.clear(); objectStorage.setItem.mockClear(); - // Since the exposed `registerStore` is a proxying function, mimic - // intercept of original call by adding an initial plugin. // TODO: Remove the `use` function in favor of `registerGenericStore` - registry = createRegistry() - .use( ( originalRegistry ) => { - originalRegisterStore = jest.spyOn( - originalRegistry, - 'registerStore' - ); - return {}; - } ) - .use( plugin, { storage: objectStorage } ); + registry = createRegistry().use( plugin, { storage: objectStorage } ); } ); it( 'should not mutate options', () => { @@ -181,17 +171,6 @@ describe( 'persistence', () => { expect( registry.select( 'test' ).getState() ).toBe( 1 ); } ); - it( 'override values passed to registerStore', () => { - const options = { persist: true, reducer() {} }; - - registry.registerStore( 'test', options ); - - expect( originalRegisterStore ).toHaveBeenCalledWith( 'test', { - persist: true, - reducer: expect.any( Function ), - } ); - } ); - it( 'should not persist if option not passed', () => { const initialState = { foo: 'bar', baz: 'qux' }; function reducer( state = initialState, action ) { diff --git a/packages/data/src/registry.js b/packages/data/src/registry.js index adb11b40c75dfa..4f74d4cb1ea512 100644 --- a/packages/data/src/registry.js +++ b/packages/data/src/registry.js @@ -32,6 +32,8 @@ import createCoreDataStore from './store'; /** * @typedef {Object} WPDataPlugin An object of registry function overrides. + * + * @property {Function} registerStore registers store. */ /** diff --git a/packages/data/src/test/registry.js b/packages/data/src/test/registry.js index 02242ecc5b283c..879050388a9512 100644 --- a/packages/data/src/test/registry.js +++ b/packages/data/src/test/registry.js @@ -396,7 +396,7 @@ describe( 'createRegistry', () => { return promise; } ); - it( 'should resolve promise non-action to dispatch', ( done ) => { + it( 'should resolve promise non-action to dispatch', () => { let shouldThrow = false; registry.registerStore( 'demo', { reducer: ( state = 'OK' ) => { @@ -417,9 +417,7 @@ describe( 'createRegistry', () => { registry.select( 'demo' ).getValue(); - process.nextTick( () => { - done(); - } ); + return new Promise( ( resolve ) => process.nextTick( resolve ) ); } ); it( 'should not dispatch resolved promise action on subsequent selector calls', () => { diff --git a/packages/date/README.md b/packages/date/README.md index e45bb664c85519..954ea388ece67d 100644 --- a/packages/date/README.md +++ b/packages/date/README.md @@ -18,26 +18,40 @@ _This package assumes that your code will run in an **ES2015+** environment. If <a name="date" href="#date">#</a> **date** -Formats a date (like `date()` in PHP), in the site's timezone. +Formats a date (like `date()` in PHP). + +_Related_ + +- <https://en.wikipedia.org/wiki/List_of_tz_database_time_zones> +- <https://en.wikipedia.org/wiki/ISO_8601#Time_offsets_from_UTC> _Parameters_ - _dateFormat_ `string`: PHP-style formatting string. See php.net/date. - _dateValue_ `(Date|string|Moment|null)`: Date object or string, parsable by moment.js. +- _timezone_ `(string|number|null)`: Timezone to output result in or a UTC offset. Defaults to timezone from site. _Returns_ -- `string`: Formatted date. +- `string`: Formatted date in English. <a name="dateI18n" href="#dateI18n">#</a> **dateI18n** -Formats a date (like `date_i18n()` in PHP). +Formats a date (like `wp_date()` in PHP), translating it into site's locale. + +Backward Compatibility Notice: if `timezone` is set to `true`, the function +behaves like `gmdateI18n`. + +_Related_ + +- <https://en.wikipedia.org/wiki/List_of_tz_database_time_zones> +- <https://en.wikipedia.org/wiki/ISO_8601#Time_offsets_from_UTC> _Parameters_ - _dateFormat_ `string`: PHP-style formatting string. See php.net/date. - _dateValue_ `(Date|string|Moment|null)`: Date object or string, parsable by moment.js. -- _gmt_ `boolean`: True for GMT/UTC, false for site's timezone. +- _timezone_ `(string|number|boolean|null)`: Timezone to output result in or a UTC offset. Defaults to timezone from site. Notice: `boolean` is effectively deprecated, but still supported for backward compatibility reasons. _Returns_ @@ -79,6 +93,20 @@ _Parameters_ _Returns_ +- `string`: Formatted date in English. + +<a name="gmdateI18n" href="#gmdateI18n">#</a> **gmdateI18n** + +Formats a date (like `wp_date()` in PHP), translating it into site's locale +and using the UTC timezone. + +_Parameters_ + +- _dateFormat_ `string`: PHP-style formatting string. See php.net/date. +- _dateValue_ `(Date|string|Moment|null)`: Date object or string, parsable by moment.js. + +_Returns_ + - `string`: Formatted date. <a name="isInTheFuture" href="#isInTheFuture">#</a> **isInTheFuture** diff --git a/packages/date/package.json b/packages/date/package.json index c095c6a6a8aac9..7a17016a652555 100644 --- a/packages/date/package.json +++ b/packages/date/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/date", - "version": "3.8.0", + "version": "3.9.0", "description": "Date module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -21,7 +21,7 @@ "module": "build-module/index.js", "react-native": "src/index", "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "moment": "^2.22.1", "moment-timezone": "^0.5.16" }, diff --git a/packages/date/src/index.js b/packages/date/src/index.js index 6251e1c82c04bf..25697d8fadd596 100644 --- a/packages/date/src/index.js +++ b/packages/date/src/index.js @@ -9,6 +9,10 @@ import 'moment-timezone/moment-timezone-utils'; const WP_ZONE = 'WP'; +// This regular expression tests positive for UTC offsets as described in ISO 8601. +// See: https://en.wikipedia.org/wiki/ISO_8601#Time_offsets_from_UTC +const VALID_UTC_OFFSET = /^[+-][0-1][0-9](:?[0-9][0-9])?$/; + // Changes made here will likely need to be made in `lib/client-assets.php` as // well because it uses the `setSettings()` function to change these settings. let settings = { @@ -318,10 +322,10 @@ const formatMap = { /** * Formats a date. Does not alter the date's timezone. * - * @param {string} dateFormat PHP-style formatting string. - * See php.net/date. - * @param {(Date|string|Moment|null)} dateValue Date object or string, - * parsable by moment.js. + * @param {string} dateFormat PHP-style formatting string. + * See php.net/date. + * @param {Date|string|Moment|null} dateValue Date object or string, + * parsable by moment.js. * * @return {string} Formatted date. */ @@ -357,30 +361,35 @@ export function format( dateFormat, dateValue = new Date() ) { } /** - * Formats a date (like `date()` in PHP), in the site's timezone. + * Formats a date (like `date()` in PHP). * - * @param {string} dateFormat PHP-style formatting string. - * See php.net/date. - * @param {(Date|string|Moment|null)} dateValue Date object or string, - * parsable by moment.js. + * @param {string} dateFormat PHP-style formatting string. + * See php.net/date. + * @param {Date|string|Moment|null} dateValue Date object or string, parsable + * by moment.js. + * @param {string|number|null} timezone Timezone to output result in or a + * UTC offset. Defaults to timezone from + * site. * - * @return {string} Formatted date. + * @see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones + * @see https://en.wikipedia.org/wiki/ISO_8601#Time_offsets_from_UTC + * + * @return {string} Formatted date in English. */ -export function date( dateFormat, dateValue = new Date() ) { - const offset = settings.timezone.offset * HOUR_IN_MINUTES; - const dateMoment = momentLib( dateValue ).utcOffset( offset, true ); +export function date( dateFormat, dateValue = new Date(), timezone ) { + const dateMoment = buildMoment( dateValue, timezone ); return format( dateFormat, dateMoment ); } /** * Formats a date (like `date()` in PHP), in the UTC timezone. * - * @param {string} dateFormat PHP-style formatting string. - * See php.net/date. - * @param {(Date|string|Moment|null)} dateValue Date object or string, - * parsable by moment.js. + * @param {string} dateFormat PHP-style formatting string. + * See php.net/date. + * @param {Date|string|Moment|null} dateValue Date object or string, + * parsable by moment.js. * - * @return {string} Formatted date. + * @return {string} Formatted date in English. */ export function gmdate( dateFormat, dateValue = new Date() ) { const dateMoment = momentLib( dateValue ).utc(); @@ -388,26 +397,54 @@ export function gmdate( dateFormat, dateValue = new Date() ) { } /** - * Formats a date (like `date_i18n()` in PHP). + * Formats a date (like `wp_date()` in PHP), translating it into site's locale. + * + * Backward Compatibility Notice: if `timezone` is set to `true`, the function + * behaves like `gmdateI18n`. + * + * @param {string} dateFormat PHP-style formatting string. + * See php.net/date. + * @param {Date|string|Moment|null} dateValue Date object or string, parsable by + * moment.js. + * @param {string|number|boolean|null} timezone Timezone to output result in or a + * UTC offset. Defaults to timezone from + * site. Notice: `boolean` is effectively + * deprecated, but still supported for + * backward compatibility reasons. * - * @param {string} dateFormat PHP-style formatting string. - * See php.net/date. - * @param {(Date|string|Moment|null)} dateValue Date object or string, - * parsable by moment.js. - * @param {boolean} gmt True for GMT/UTC, false for - * site's timezone. + * @see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones + * @see https://en.wikipedia.org/wiki/ISO_8601#Time_offsets_from_UTC * * @return {string} Formatted date. */ -export function dateI18n( dateFormat, dateValue = new Date(), gmt = false ) { - // Defaults. - const offset = gmt ? 0 : settings.timezone.offset * HOUR_IN_MINUTES; - // Convert to moment object. - const dateMoment = momentLib( dateValue ).utcOffset( offset, true ); +export function dateI18n( dateFormat, dateValue = new Date(), timezone ) { + if ( true === timezone ) { + return gmdateI18n( dateFormat, dateValue ); + } + + if ( false === timezone ) { + timezone = undefined; + } - // Set the locale. + const dateMoment = buildMoment( dateValue, timezone ); + dateMoment.locale( settings.l10n.locale ); + return format( dateFormat, dateMoment ); +} + +/** + * Formats a date (like `wp_date()` in PHP), translating it into site's locale + * and using the UTC timezone. + * + * @param {string} dateFormat PHP-style formatting string. + * See php.net/date. + * @param {Date|string|Moment|null} dateValue Date object or string, + * parsable by moment.js. + * + * @return {string} Formatted date. + */ +export function gmdateI18n( dateFormat, dateValue = new Date() ) { + const dateMoment = momentLib( dateValue ).utc(); dateMoment.locale( settings.l10n.locale ); - // Format and return. return format( dateFormat, dateMoment ); } @@ -440,4 +477,51 @@ export function getDate( dateString ) { return momentLib.tz( dateString, WP_ZONE ).toDate(); } +/** + * Creates a moment instance using the given timezone or, if none is provided, using global settings. + * + * @param {Date|string|Moment|null} dateValue Date object or string, parsable + * by moment.js. + * @param {string|number|null} timezone Timezone to output result in or a + * UTC offset. Defaults to timezone from + * site. + * + * @see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones + * @see https://en.wikipedia.org/wiki/ISO_8601#Time_offsets_from_UTC + * + * @return {Moment} a moment instance. + */ +function buildMoment( dateValue, timezone = '' ) { + const dateMoment = momentLib( dateValue ); + + if ( timezone && ! isUTCOffset( timezone ) ) { + return dateMoment.tz( timezone ); + } + + if ( timezone && isUTCOffset( timezone ) ) { + return dateMoment.utcOffset( timezone ); + } + + if ( settings.timezone.string ) { + return dateMoment.tz( settings.timezone.string ); + } + + return dateMoment.utcOffset( settings.timezone.offset ); +} + +/** + * Returns whether a certain UTC offset is valid or not. + * + * @param {number|string} offset a UTC offset. + * + * @return {boolean} whether a certain UTC offset is valid or not. + */ +function isUTCOffset( offset ) { + if ( 'number' === typeof offset ) { + return true; + } + + return VALID_UTC_OFFSET.test( offset ); +} + setupWPTimezone(); diff --git a/packages/date/src/test/index.js b/packages/date/src/test/index.js index 69368b1fb630b5..d9b832e528ce6b 100644 --- a/packages/date/src/test/index.js +++ b/packages/date/src/test/index.js @@ -2,10 +2,14 @@ * Internal dependencies */ import { - isInTheFuture, + __experimentalGetSettings, + date as dateNoI18n, + dateI18n, getDate, + gmdate, + gmdateI18n, + isInTheFuture, setSettings, - __experimentalGetSettings, } from '../'; describe( 'isInTheFuture', () => { @@ -16,7 +20,7 @@ describe( 'isInTheFuture', () => { expect( isInTheFuture( date ) ).toBe( true ); } ); - it( 'should return true if the date is in the past', () => { + it( 'should return false if the date is in the past', () => { // Create a Date object 1 minute in the past. const date = new Date( Number( getDate() ) - 1000 * 60 ); @@ -44,6 +48,433 @@ describe( 'isInTheFuture', () => { } ); } ); +describe( 'Function date', () => { + it( 'should format date in English, ignoring locale settings', () => { + const settings = __experimentalGetSettings(); + + // Simulate different locale + const l10n = settings.l10n; + setSettings( { + ...settings, + l10n: { + ...l10n, + locale: 'es', + months: l10n.months.map( ( month ) => `es_${ month }` ), + monthsShort: l10n.monthsShort.map( + ( month ) => `es_${ month }` + ), + weekdays: l10n.weekdays.map( ( weekday ) => `es_${ weekday }` ), + weekdaysShort: l10n.weekdaysShort.map( + ( weekday ) => `es_${ weekday }` + ), + }, + } ); + + // Check + const formattedDate = dateNoI18n( + 'F M l D', + '2019-06-18T11:00:00.000Z' + ); + expect( formattedDate ).toBe( 'June Jun Tuesday Tue' ); + + // Restore default settings + setSettings( settings ); + } ); + + it( 'should format date into a date that uses site’s timezone, if no timezone was provided and there’s a site timezone set', () => { + const settings = __experimentalGetSettings(); + + // Simulate different timezone + setSettings( { + ...settings, + timezone: { offset: -4, string: 'America/New_York' }, + } ); + + // Check + const winterFormattedDate = dateNoI18n( + 'Y-m-d H:i', + '2019-01-18T11:00:00.000Z' + ); + expect( winterFormattedDate ).toBe( '2019-01-18 06:00' ); + + const summerFormattedDate = dateNoI18n( + 'Y-m-d H:i', + '2019-06-18T11:00:00.000Z' + ); + expect( summerFormattedDate ).toBe( '2019-06-18 07:00' ); + + // Restore default settings + setSettings( settings ); + } ); + + it( 'should format date into a date that uses site’s UTC offset setting, if no timezone was provided and there isn’t a timezone set in the site', () => { + const settings = __experimentalGetSettings(); + + // Simulate different timezone + setSettings( { + ...settings, + timezone: { offset: -4, string: '' }, + } ); + + // Check + const winterFormattedDate = dateNoI18n( + 'Y-m-d H:i', + '2019-01-18T11:00:00.000Z' + ); + expect( winterFormattedDate ).toBe( '2019-01-18 07:00' ); + + const summerFormattedDate = dateNoI18n( + 'Y-m-d H:i', + '2019-06-18T11:00:00.000Z' + ); + expect( summerFormattedDate ).toBe( '2019-06-18 07:00' ); + + // Restore default settings + setSettings( settings ); + } ); + + it( 'should format date into a date that uses the given timezone, if said timezone is valid', () => { + const settings = __experimentalGetSettings(); + + // Simulate different timezone + setSettings( { + ...settings, + timezone: { offset: -4, string: 'America/New_York' }, + } ); + + // Check + const formattedDate = dateNoI18n( + 'Y-m-d H:i', + '2019-06-18T11:00:00.000Z', + 'Asia/Macau' + ); + expect( formattedDate ).toBe( '2019-06-18 19:00' ); + + // Restore default settings + setSettings( settings ); + } ); + + it( 'should format date into a date that uses the given UTC offset, if given timezone is actually a UTC offset', () => { + const settings = __experimentalGetSettings(); + + // Simulate different timezone + setSettings( { + ...settings, + timezone: { offset: -4, string: 'America/New_York' }, + } ); + + // Check + let formattedDate; + formattedDate = dateNoI18n( + 'Y-m-d H:i', + '2019-06-18T11:00:00.000Z', + '+08:00' + ); + expect( formattedDate ).toBe( '2019-06-18 19:00' ); + + formattedDate = dateNoI18n( + 'Y-m-d H:i', + '2019-06-18T11:00:00.000Z', + 8 + ); + expect( formattedDate ).toBe( '2019-06-18 19:00' ); + + formattedDate = dateNoI18n( + 'Y-m-d H:i', + '2019-06-18T11:00:00.000Z', + 480 + ); + expect( formattedDate ).toBe( '2019-06-18 19:00' ); + + // Restore default settings + setSettings( settings ); + } ); +} ); + +describe( 'Function gmdate', () => { + it( 'should format date in English, ignoring locale settings', () => { + const settings = __experimentalGetSettings(); + + // Simulate different locale + const l10n = settings.l10n; + setSettings( { + ...settings, + l10n: { + ...l10n, + locale: 'es', + months: l10n.months.map( ( month ) => `es_${ month }` ), + monthsShort: l10n.monthsShort.map( + ( month ) => `es_${ month }` + ), + weekdays: l10n.weekdays.map( ( weekday ) => `es_${ weekday }` ), + weekdaysShort: l10n.weekdaysShort.map( + ( weekday ) => `es_${ weekday }` + ), + }, + } ); + + // Check + const formattedDate = gmdate( 'F M l D', '2019-06-18T11:00:00.000Z' ); + expect( formattedDate ).toBe( 'June Jun Tuesday Tue' ); + + // Restore default settings + setSettings( settings ); + } ); + + it( 'should format date into a UTC date', () => { + const settings = __experimentalGetSettings(); + + // Simulate different timezone + setSettings( { + ...settings, + timezone: { offset: -4, string: 'America/New_York' }, + } ); + + // Check + const formattedDate = gmdate( 'Y-m-d H:i', '2019-06-18T11:00:00.000Z' ); + expect( formattedDate ).toBe( '2019-06-18 11:00' ); + + // Restore default settings + setSettings( settings ); + } ); +} ); + +describe( 'Function dateI18n', () => { + it( 'should format date using locale settings', () => { + const settings = __experimentalGetSettings(); + + // Simulate different locale + const l10n = settings.l10n; + setSettings( { + ...settings, + l10n: { + ...l10n, + locale: 'es', + months: l10n.months.map( ( month ) => `es_${ month }` ), + monthsShort: l10n.monthsShort.map( + ( month ) => `es_${ month }` + ), + weekdays: l10n.weekdays.map( ( weekday ) => `es_${ weekday }` ), + weekdaysShort: l10n.weekdaysShort.map( + ( weekday ) => `es_${ weekday }` + ), + }, + } ); + + // Check + const formattedDate = dateI18n( + 'F M l D', + '2019-06-18T11:00:00.000Z', + true + ); + expect( formattedDate ).toBe( 'es_June es_Jun es_Tuesday es_Tue' ); + + // Restore default settings + setSettings( settings ); + } ); + + it( 'should format date into a date that uses site’s timezone, if no timezone was provided and there’s a site timezone set', () => { + const settings = __experimentalGetSettings(); + + // Simulate different timezone + setSettings( { + ...settings, + timezone: { offset: -4, string: 'America/New_York' }, + } ); + + // Check + const winterFormattedDate = dateI18n( + 'Y-m-d H:i', + '2019-01-18T11:00:00.000Z' + ); + expect( winterFormattedDate ).toBe( '2019-01-18 06:00' ); + + const summerFormattedDate = dateI18n( + 'Y-m-d H:i', + '2019-06-18T11:00:00.000Z' + ); + expect( summerFormattedDate ).toBe( '2019-06-18 07:00' ); + + // Restore default settings + setSettings( settings ); + } ); + + it( 'should format date into a date that uses site’s UTC offset setting, if no timezone was provided and there isn’t a timezone set in the site', () => { + const settings = __experimentalGetSettings(); + + // Simulate different timezone + setSettings( { + ...settings, + timezone: { offset: -4, string: '' }, + } ); + + // Check + const winterFormattedDate = dateI18n( + 'Y-m-d H:i', + '2019-01-18T11:00:00.000Z' + ); + expect( winterFormattedDate ).toBe( '2019-01-18 07:00' ); + + const summerFormattedDate = dateI18n( + 'Y-m-d H:i', + '2019-06-18T11:00:00.000Z' + ); + expect( summerFormattedDate ).toBe( '2019-06-18 07:00' ); + + // Restore default settings + setSettings( settings ); + } ); + + it( 'should format date into a date that uses the given timezone, if said timezone is valid', () => { + const settings = __experimentalGetSettings(); + + // Simulate different timezone + setSettings( { + ...settings, + timezone: { offset: -4, string: 'America/New_York' }, + } ); + + // Check + const formattedDate = dateI18n( + 'Y-m-d H:i', + '2019-06-18T11:00:00.000Z', + 'Asia/Macau' + ); + expect( formattedDate ).toBe( '2019-06-18 19:00' ); + + // Restore default settings + setSettings( settings ); + } ); + + it( 'should format date into a date that uses the given UTC offset, if given timezone is actually a UTC offset', () => { + const settings = __experimentalGetSettings(); + + // Simulate different timezone + setSettings( { + ...settings, + timezone: { offset: -4, string: 'America/New_York' }, + } ); + + // Check + let formattedDate; + formattedDate = dateI18n( + 'Y-m-d H:i', + '2019-06-18T11:00:00.000Z', + '+08:00' + ); + expect( formattedDate ).toBe( '2019-06-18 19:00' ); + + formattedDate = dateI18n( 'Y-m-d H:i', '2019-06-18T11:00:00.000Z', 8 ); + expect( formattedDate ).toBe( '2019-06-18 19:00' ); + + formattedDate = dateI18n( + 'Y-m-d H:i', + '2019-06-18T11:00:00.000Z', + 480 + ); + expect( formattedDate ).toBe( '2019-06-18 19:00' ); + + // Restore default settings + setSettings( settings ); + } ); + + it( 'should format date into a UTC date if `gmt` is set to `true`', () => { + const settings = __experimentalGetSettings(); + + // Simulate different timezone + setSettings( { + ...settings, + timezone: { offset: -4, string: 'America/New_York' }, + } ); + + // Check + const formattedDate = dateI18n( + 'Y-m-d H:i', + '2019-06-18T11:00:00.000Z', + true + ); + expect( formattedDate ).toBe( '2019-06-18 11:00' ); + + // Restore default settings + setSettings( settings ); + } ); + + it( 'should format date into a date that uses site’s timezone if `gmt` is set to `false`', () => { + const settings = __experimentalGetSettings(); + + // Simulate different timezone + setSettings( { + ...settings, + timezone: { offset: -4, string: 'America/New_York' }, + } ); + + // Check + const formattedDate = dateI18n( + 'Y-m-d H:i', + '2019-06-18T11:00:00.000Z', + false + ); + expect( formattedDate ).toBe( '2019-06-18 07:00' ); + + // Restore default settings + setSettings( settings ); + } ); +} ); + +describe( 'Function gmdateI18n', () => { + it( 'should format date using locale settings', () => { + const settings = __experimentalGetSettings(); + + // Simulate different locale + const l10n = settings.l10n; + setSettings( { + ...settings, + l10n: { + ...l10n, + locale: 'es', + months: l10n.months.map( ( month ) => `es_${ month }` ), + monthsShort: l10n.monthsShort.map( + ( month ) => `es_${ month }` + ), + weekdays: l10n.weekdays.map( ( weekday ) => `es_${ weekday }` ), + weekdaysShort: l10n.weekdaysShort.map( + ( weekday ) => `es_${ weekday }` + ), + }, + } ); + + // Check + const formattedDate = gmdateI18n( + 'F M l D', + '2019-06-18T11:00:00.000Z' + ); + expect( formattedDate ).toBe( 'es_June es_Jun es_Tuesday es_Tue' ); + + // Restore default settings + setSettings( settings ); + } ); + + it( 'should format date into a UTC date', () => { + const settings = __experimentalGetSettings(); + + // Simulate different timezone + setSettings( { + ...settings, + timezone: { offset: -4, string: 'America/New_York' }, + } ); + + // Check + const formattedDate = gmdateI18n( + 'Y-m-d H:i', + '2019-06-18T11:00:00.000Z' + ); + expect( formattedDate ).toBe( '2019-06-18 11:00' ); + + // Restore default settings + setSettings( settings ); + } ); +} ); + describe( 'Moment.js Localization', () => { it( 'should change the relative time strings', () => { const settings = __experimentalGetSettings(); diff --git a/packages/dependency-extraction-webpack-plugin/CHANGELOG.md b/packages/dependency-extraction-webpack-plugin/CHANGELOG.md index 3505c6e0b62c1b..8755a3340d97c2 100644 --- a/packages/dependency-extraction-webpack-plugin/CHANGELOG.md +++ b/packages/dependency-extraction-webpack-plugin/CHANGELOG.md @@ -1,5 +1,7 @@ ## Master +## 2.5.0 (2020-04-01) + ### New Features - The plugin now supports an optional `combinedOutputFile` option that is useful only when another `combineAssets` option is enabled. It allows providing a custom output file for the generated single assets file ([#20844](https://github.com/WordPress/gutenberg/pull/20844)). diff --git a/packages/dependency-extraction-webpack-plugin/package.json b/packages/dependency-extraction-webpack-plugin/package.json index 3bfd70b7615513..85919790b795bf 100644 --- a/packages/dependency-extraction-webpack-plugin/package.json +++ b/packages/dependency-extraction-webpack-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/dependency-extraction-webpack-plugin", - "version": "2.4.0", + "version": "2.5.0", "description": "Extract WordPress script dependencies from webpack bundles.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/dependency-extraction-webpack-plugin/test/util.js b/packages/dependency-extraction-webpack-plugin/test/util.js index 65bd0110ff105f..8c33eb5f25b370 100644 --- a/packages/dependency-extraction-webpack-plugin/test/util.js +++ b/packages/dependency-extraction-webpack-plugin/test/util.js @@ -2,10 +2,30 @@ * Internal dependencies */ const { + camelCaseDash, defaultRequestToExternal, defaultRequestToHandle, } = require( '../util' ); +describe( 'camelCaseDash', () => { + test( 'does not change a single word', () => { + expect( camelCaseDash( 'blocks' ) ).toBe( 'blocks' ); + expect( camelCaseDash( 'dom' ) ).toBe( 'dom' ); + } ); + + test( 'does not capitalize letters following numbers', () => { + expect( camelCaseDash( 'a11y' ) ).toBe( 'a11y' ); + expect( camelCaseDash( 'i18n' ) ).toBe( 'i18n' ); + } ); + + test( 'converts dashes into camel case', () => { + expect( camelCaseDash( 'api-fetch' ) ).toBe( 'apiFetch' ); + expect( camelCaseDash( 'list-reusable-blocks' ) ).toBe( + 'listReusableBlocks' + ); + } ); +} ); + describe( 'defaultRequestToExternal', () => { test( 'Returns undefined on unrecognized request', () => { expect( defaultRequestToExternal( 'unknown-request' ) ).toBeUndefined(); diff --git a/packages/dependency-extraction-webpack-plugin/util.js b/packages/dependency-extraction-webpack-plugin/util.js index 5185c24682fb6d..b869df904787da 100644 --- a/packages/dependency-extraction-webpack-plugin/util.js +++ b/packages/dependency-extraction-webpack-plugin/util.js @@ -1,5 +1,5 @@ const WORDPRESS_NAMESPACE = '@wordpress/'; -const BUNDLED_PACKAGES = [ '@wordpress/icons' ]; +const BUNDLED_PACKAGES = [ '@wordpress/icons', '@wordpress/interface' ]; /** * Default request to global transformation @@ -79,8 +79,6 @@ function defaultRequestToHandle( request ) { * converting to uppercase, where Lodash will also capitalize letters * following numbers. * - * Temporarily duplicated from @wordpress/scripts/utils. - * * @param {string} string Input dash-delimited string. * * @return {string} Camel-cased string. @@ -92,6 +90,7 @@ function camelCaseDash( string ) { } module.exports = { + camelCaseDash, defaultRequestToExternal, defaultRequestToHandle, }; diff --git a/packages/deprecated/package.json b/packages/deprecated/package.json index fd5b82f0a52da1..a1da68e6648d57 100644 --- a/packages/deprecated/package.json +++ b/packages/deprecated/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/deprecated", - "version": "2.7.0", + "version": "2.8.0", "description": "Deprecation utility for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -22,7 +22,7 @@ "react-native": "src/index", "sideEffects": false, "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/hooks": "file:../hooks" }, "publishConfig": { diff --git a/packages/docgen/README.md b/packages/docgen/README.md index c62b96fc4e44b4..e39594cb4fc644 100644 --- a/packages/docgen/README.md +++ b/packages/docgen/README.md @@ -33,9 +33,9 @@ This command will generate a file named `entry-point-api.md` containing all the * **--output** `(String)`: Output file that will contain the API documentation. * **--to-section** `(String)`: Append generated documentation to this section in the Markdown output. To be used by the default Markdown formatter. Depends on `--output` and bypasses the custom `--formatter` passed, if any. * **--to-token**: Embed generated documentation within the start and end tokens in the Markdown output. To be used by the default Markdown formatter.Depends on `--output` and bypasses the custom `--formatter` passed, if any. - * Start token: `<!-- START TOKEN(Autogenerated API docs) -->` - * End token: `<!-- END TOKEN(Autogenerated API docs) -->` -* **--use-token** `(String)`: This options allows you to customize the string between the tokens. For example, `--use-token my-api` will look up for the start token `<!-- START TOKEN(my-api) -->` and the end token `<!-- END TOKEN(my-api) -->`. Depends on `--to-token`. + * Start token: <code>&lt;!-- START TOKEN(Autogenerated API docs) --&gt;</code> + * End token: <code>&lt;!-- END TOKEN(Autogenerated API docs) --&gt;</code> +* **--use-token** `(String)`: This options allows you to customize the string between the tokens. For example, `--use-token my-api` will look up for the start token <code>&lt;!-- START TOKEN(my-api) --&gt;</code> and the end token <code>&lt;!-- END TOKEN(my-api) --&gt;</code>. Depends on `--to-token`. * **--debug**: Run in debug mode, which outputs some intermediate files useful for debugging. ## Examples diff --git a/packages/docgen/package.json b/packages/docgen/package.json index d0fc143594a7c6..8ce4df2ccb83ee 100644 --- a/packages/docgen/package.json +++ b/packages/docgen/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/docgen", - "version": "1.7.0", + "version": "1.8.0", "description": "Autogenerate public API documentation from exports and JSDoc comments.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/docgen/src/test/fixtures/tags-function/code.js b/packages/docgen/src/test/fixtures/tags-function/code.js index cbde0e0b9b0456..4e0bd9644fb90b 100644 --- a/packages/docgen/src/test/fixtures/tags-function/code.js +++ b/packages/docgen/src/test/fixtures/tags-function/code.js @@ -2,7 +2,7 @@ * A function that adds two parameters. * * @deprecated Use native addition instead. - * @since v2 + * @since 2.0.0 * * @see addition * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators diff --git a/packages/dom-ready/CHANGELOG.md b/packages/dom-ready/CHANGELOG.md index 116d21d37d4214..5fd9d40b62cf4d 100644 --- a/packages/dom-ready/CHANGELOG.md +++ b/packages/dom-ready/CHANGELOG.md @@ -1,3 +1,11 @@ +## Master + +## 2.9.0 (2020-04-15) + +### New feature + +- Include TypeScript type declarations ([#18942](https://github.com/WordPress/gutenberg/pull/18942)) + ## 2.0.0 (2018-09-05) ### Breaking Change diff --git a/packages/dom-ready/package.json b/packages/dom-ready/package.json index 6fd51bdd0b7144..4525e71e5f0912 100644 --- a/packages/dom-ready/package.json +++ b/packages/dom-ready/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/dom-ready", - "version": "2.7.0", + "version": "2.9.0", "description": "Execute callback after the DOM is loaded.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -20,9 +20,10 @@ "main": "build/index.js", "module": "build-module/index.js", "react-native": "src/index", + "types": "build-types", "sideEffects": false, "dependencies": { - "@babel/runtime": "^7.8.3" + "@babel/runtime": "^7.9.2" }, "publishConfig": { "access": "public" diff --git a/packages/dom-ready/tsconfig.json b/packages/dom-ready/tsconfig.json new file mode 100644 index 00000000000000..3c2c31f506f132 --- /dev/null +++ b/packages/dom-ready/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "src", + "declarationDir": "build-types" + }, + "include": [ "src/**/*" ] +} diff --git a/packages/dom/README.md b/packages/dom/README.md index d52e47552f342e..d45b8439915786 100644 --- a/packages/dom/README.md +++ b/packages/dom/README.md @@ -118,6 +118,19 @@ _Returns_ - `boolean`: True if at the horizontal edge, false if not. +<a name="isNumberInput" href="#isNumberInput">#</a> **isNumberInput** + +Check whether the given element is an input field of type number +and has a valueAsNumber + +_Parameters_ + +- _element_ `HTMLElement`: The HTML element. + +_Returns_ + +- `boolean`: True if the element is input and holds a number. + <a name="isTextField" href="#isTextField">#</a> **isTextField** Check whether the given element is a text field, where text field is defined diff --git a/packages/dom/package.json b/packages/dom/package.json index e0199899bb23a3..73284a801a4e25 100644 --- a/packages/dom/package.json +++ b/packages/dom/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/dom", - "version": "2.8.0", + "version": "2.9.0", "description": "DOM utilities module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -23,7 +23,7 @@ "react-native": "src/index", "sideEffects": false, "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "lodash": "^4.17.15" }, "publishConfig": { diff --git a/packages/dom/src/dom.js b/packages/dom/src/dom.js index c1ae1fbc17395d..8271abe1efcd9f 100644 --- a/packages/dom/src/dom.js +++ b/packages/dom/src/dom.js @@ -469,6 +469,20 @@ export function isTextField( element ) { } } +/** + * Check whether the given element is an input field of type number + * and has a valueAsNumber + * + * @param {HTMLElement} element The HTML element. + * + * @return {boolean} True if the element is input and holds a number. + */ +export function isNumberInput( element ) { + const { nodeName, type, valueAsNumber } = element; + + return nodeName === 'INPUT' && type === 'number' && !! valueAsNumber; +} + /** * Check wether the current document has a selection. * This checks both for focus in an input field and general text selection. @@ -480,6 +494,10 @@ export function documentHasSelection() { return true; } + if ( isNumberInput( document.activeElement ) ) { + return true; + } + const selection = window.getSelection(); const range = selection.rangeCount ? selection.getRangeAt( 0 ) : null; diff --git a/packages/dom/src/test/dom.js b/packages/dom/src/test/dom.js index a2352d75efbd8a..eabb2ed968bd1a 100644 --- a/packages/dom/src/test/dom.js +++ b/packages/dom/src/test/dom.js @@ -6,6 +6,7 @@ import { placeCaretAtHorizontalEdge, isTextField, __unstableStripHTML as stripHTML, + isNumberInput, } from '../dom'; describe( 'DOM', () => { @@ -143,6 +144,21 @@ describe( 'DOM', () => { ); } ); + it( 'should return false for empty input element of type number', () => { + const input = document.createElement( 'input' ); + input.type = 'number'; + + expect( isNumberInput( input ) ).toBe( false ); + } ); + + it( 'should return true for an input element of type number', () => { + const input = document.createElement( 'input' ); + input.type = 'number'; + input.valueAsNumber = 23; + + expect( isNumberInput( input ) ).toBe( true ); + } ); + it( 'should return true for a contenteditable element', () => { const div = document.createElement( 'div' ); diff --git a/packages/e2e-test-utils/CHANGELOG.md b/packages/e2e-test-utils/CHANGELOG.md index f995fb1336bcf4..6d466ba2875021 100644 --- a/packages/e2e-test-utils/CHANGELOG.md +++ b/packages/e2e-test-utils/CHANGELOG.md @@ -1,3 +1,15 @@ +## Master + +## 4.5.0 (2020-04-15) + +### Enhancements + +- `visitAdminPage` will now throw an error (emit a test failure) when there are unexpected errors on hte page. + +### New Features + +- Added `getPageError` function, returning a promise which resolves to an error message present in the page, if any exists. + ## 4.0.0 (2019-12-19) ### Breaking Changes diff --git a/packages/e2e-test-utils/README.md b/packages/e2e-test-utils/README.md index d397bce0bf6470..1e84e815f74dc3 100644 --- a/packages/e2e-test-utils/README.md +++ b/packages/e2e-test-utils/README.md @@ -72,6 +72,10 @@ _Parameters_ - _buttonLabel_ `string`: The label to search the button for. +<a name="closeGlobalBlockInserter" href="#closeGlobalBlockInserter">#</a> **closeGlobalBlockInserter** + +Undocumented declaration. + <a name="createEmbeddingMatcher" href="#createEmbeddingMatcher">#</a> **createEmbeddingMatcher** Creates a function to determine if a request is embedding a certain URL. @@ -252,6 +256,21 @@ _Returns_ - `Promise`: Promise resolving with post content markup. +<a name="getPageError" href="#getPageError">#</a> **getPageError** + +Returns a promise resolving to one of either a string or null. A string will +be resolved if an error message is present in the contents of the page. If no +error is present, a null value will be resolved instead. This requires the +environment be configured to display errors. + +_Related_ + +- <http://php.net/manual/en/function.error-reporting.php> + +_Returns_ + +- `Promise<?string>`: Promise resolving to a string or null, depending whether a page error is present. + <a name="hasBlockSwitcher" href="#hasBlockSwitcher">#</a> **hasBlockSwitcher** Returns a boolean indicating if the current selected block has a block switcher or not. @@ -268,7 +287,6 @@ result that appears. _Parameters_ - _searchTerm_ `string`: The text to search the inserter for. -- _panelName_ `string`: The inserter panel to open (if it's closed by default). <a name="installPlugin" href="#installPlugin">#</a> **installPlugin** @@ -328,10 +346,6 @@ _Returns_ - `Promise`: Promise that uses `mockCheck` to see if a request should be mocked with `mock`, and optionally transforms the response with `responseObjectTransform`. -<a name="openAllBlockInserterCategories" href="#openAllBlockInserterCategories">#</a> **openAllBlockInserterCategories** - -Opens all block inserter categories. - <a name="openDocumentSettingsSidebar" href="#openDocumentSettingsSidebar">#</a> **openDocumentSettingsSidebar** Clicks on the button in the header which opens Document Settings sidebar when it is closed. diff --git a/packages/e2e-test-utils/package.json b/packages/e2e-test-utils/package.json index aad54b05d6515e..4136672e941879 100644 --- a/packages/e2e-test-utils/package.json +++ b/packages/e2e-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/e2e-test-utils", - "version": "4.3.1", + "version": "4.5.0", "description": "End-To-End (E2E) test utils for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -28,7 +28,7 @@ "main": "build/index.js", "module": "build-module/index.js", "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/keycodes": "file:../keycodes", "@wordpress/url": "file:../url", "lodash": "^4.17.15", diff --git a/packages/e2e-test-utils/src/get-all-block-inserter-item-titles.js b/packages/e2e-test-utils/src/get-all-block-inserter-item-titles.js index eb2802e879b559..b9bc3b058a0c1c 100644 --- a/packages/e2e-test-utils/src/get-all-block-inserter-item-titles.js +++ b/packages/e2e-test-utils/src/get-all-block-inserter-item-titles.js @@ -12,7 +12,7 @@ export async function getAllBlockInserterItemTitles() { const inserterItemTitles = await page.evaluate( () => { return Array.from( document.querySelectorAll( - '.block-editor-inserter__results .block-editor-block-types-list__item-title' + '.block-editor-inserter__block-list .block-editor-block-types-list__item-title' ) ).map( ( inserterItem ) => { return inserterItem.innerText; diff --git a/packages/e2e-test-utils/src/get-available-block-transforms.js b/packages/e2e-test-utils/src/get-available-block-transforms.js index 1b3074f0c501a7..eeadabea18f360 100644 --- a/packages/e2e-test-utils/src/get-available-block-transforms.js +++ b/packages/e2e-test-utils/src/get-available-block-transforms.js @@ -22,5 +22,5 @@ export const getAvailableBlockTransforms = async () => { return button.textContent; } ); - }, '.block-editor-block-types-list .block-editor-block-types-list__list-item button' ); + }, '.block-editor-block-switcher__popover .block-editor-block-types-list .block-editor-block-types-list__list-item button' ); }; diff --git a/packages/e2e-test-utils/src/get-page-error.js b/packages/e2e-test-utils/src/get-page-error.js new file mode 100644 index 00000000000000..0182119ce7e38e --- /dev/null +++ b/packages/e2e-test-utils/src/get-page-error.js @@ -0,0 +1,25 @@ +/** + * Regular expression matching a displayed PHP error within a markup string. + * + * @see https://github.com/php/php-src/blob/598175e/main/main.c#L1257-L1297 + * + * @type {RegExp} + */ +const REGEXP_PHP_ERROR = /(<b>)?(Fatal error|Recoverable fatal error|Warning|Parse error|Notice|Strict Standards|Deprecated|Unknown error)(<\/b>)?: (.*?) in (.*?) on line (<b>)?\d+(<\/b>)?/; + +/** + * Returns a promise resolving to one of either a string or null. A string will + * be resolved if an error message is present in the contents of the page. If no + * error is present, a null value will be resolved instead. This requires the + * environment be configured to display errors. + * + * @see http://php.net/manual/en/function.error-reporting.php + * + * @return {Promise<?string>} Promise resolving to a string or null, depending + * whether a page error is present. + */ +export async function getPageError() { + const content = await page.content(); + const match = content.match( REGEXP_PHP_ERROR ); + return match ? match[ 0 ] : null; +} diff --git a/packages/e2e-test-utils/src/index.js b/packages/e2e-test-utils/src/index.js index 136496058223b4..422eca76bee4a3 100644 --- a/packages/e2e-test-utils/src/index.js +++ b/packages/e2e-test-utils/src/index.js @@ -22,6 +22,7 @@ export { getAvailableBlockTransforms } from './get-available-block-transforms'; export { getBlockSetting } from './get-block-setting'; export { getEditedPostContent } from './get-edited-post-content'; export { hasBlockSwitcher } from './has-block-switcher'; +export { getPageError } from './get-page-error'; export { insertBlock } from './insert-block'; export { installPlugin } from './install-plugin'; export { isCurrentURL } from './is-current-url'; @@ -31,9 +32,11 @@ export { enableFocusLossObservation, disableFocusLossObservation, } from './observe-focus-loss'; -export { openAllBlockInserterCategories } from './open-all-block-inserter-categories'; export { openDocumentSettingsSidebar } from './open-document-settings-sidebar'; -export { openGlobalBlockInserter } from './open-global-block-inserter'; +export { + openGlobalBlockInserter, + closeGlobalBlockInserter, +} from './open-global-block-inserter'; export { openPublishPanel } from './open-publish-panel'; export { pressKeyTimes } from './press-key-times'; export { pressKeyWithModifier } from './press-key-with-modifier'; diff --git a/packages/e2e-test-utils/src/insert-block.js b/packages/e2e-test-utils/src/insert-block.js index 4190d7c1136ce3..a3a31994165969 100644 --- a/packages/e2e-test-utils/src/insert-block.js +++ b/packages/e2e-test-utils/src/insert-block.js @@ -8,16 +8,9 @@ import { searchForBlock } from './search-for-block'; * result that appears. * * @param {string} searchTerm The text to search the inserter for. - * @param {string} panelName The inserter panel to open (if it's closed by default). */ -export async function insertBlock( searchTerm, panelName = null ) { +export async function insertBlock( searchTerm ) { await searchForBlock( searchTerm ); - if ( panelName ) { - const panelButton = ( - await page.$x( `//button[contains(text(), '${ panelName }')]` ) - )[ 0 ]; - await panelButton.click(); - } const insertButton = ( await page.$x( `//button//span[contains(text(), '${ searchTerm }')]` ) )[ 0 ]; diff --git a/packages/e2e-test-utils/src/open-all-block-inserter-categories.js b/packages/e2e-test-utils/src/open-all-block-inserter-categories.js deleted file mode 100644 index 9b31a0cd36c4ae..00000000000000 --- a/packages/e2e-test-utils/src/open-all-block-inserter-categories.js +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Opens all block inserter categories. - */ -export async function openAllBlockInserterCategories() { - const notOppenedCategorySelector = - '.block-editor-inserter__results .components-panel__body:not(.is-opened)'; - let categoryPanel = await page.$( notOppenedCategorySelector ); - while ( categoryPanel !== null ) { - await categoryPanel.click(); - categoryPanel = await page.$( notOppenedCategorySelector ); - } -} diff --git a/packages/e2e-test-utils/src/open-global-block-inserter.js b/packages/e2e-test-utils/src/open-global-block-inserter.js index 5bbd83a0d86289..2e39325f763b21 100644 --- a/packages/e2e-test-utils/src/open-global-block-inserter.js +++ b/packages/e2e-test-utils/src/open-global-block-inserter.js @@ -2,8 +2,31 @@ * Opens the global block inserter. */ export async function openGlobalBlockInserter() { - await page.click( '.edit-post-header [aria-label="Add block"]' ); - // Waiting here is necessary because sometimes the inserter takes more time to - // render than Puppeteer takes to complete the 'click' action - await page.waitForSelector( '.block-editor-inserter__menu' ); + if ( ! ( await isGlobalInserterOpen() ) ) { + await toggleGlobalBlockInserter(); + + // Waiting here is necessary because sometimes the inserter takes more time to + // render than Puppeteer takes to complete the 'click' action + await page.waitForSelector( '.block-editor-inserter__menu' ); + } +} + +export async function closeGlobalBlockInserter() { + if ( await isGlobalInserterOpen() ) { + await toggleGlobalBlockInserter(); + } +} + +async function isGlobalInserterOpen() { + return await page.evaluate( () => { + return !! document.querySelector( + '.edit-post-header [aria-label="Add block"].is-pressed, .edit-site-header [aria-label="Add block"].is-pressed' + ); + } ); +} + +async function toggleGlobalBlockInserter() { + await page.click( + '.edit-post-header [aria-label="Add block"], .edit-site-header [aria-label="Add block"]' + ); } diff --git a/packages/e2e-test-utils/src/search-for-block.js b/packages/e2e-test-utils/src/search-for-block.js index bf8b7cd1e74d4c..2763d98f614923 100644 --- a/packages/e2e-test-utils/src/search-for-block.js +++ b/packages/e2e-test-utils/src/search-for-block.js @@ -2,6 +2,7 @@ * Internal dependencies */ import { openGlobalBlockInserter } from './open-global-block-inserter'; +import { pressKeyWithModifier } from './press-key-with-modifier'; /** * Search for block in the global inserter @@ -10,5 +11,7 @@ import { openGlobalBlockInserter } from './open-global-block-inserter'; */ export async function searchForBlock( searchTerm ) { await openGlobalBlockInserter(); + await page.focus( '.block-editor-inserter__search-input' ); + await pressKeyWithModifier( 'primary', 'a' ); await page.keyboard.type( searchTerm ); } diff --git a/packages/e2e-test-utils/src/test/get-page-error.js b/packages/e2e-test-utils/src/test/get-page-error.js new file mode 100644 index 00000000000000..ef8c113372f35c --- /dev/null +++ b/packages/e2e-test-utils/src/test/get-page-error.js @@ -0,0 +1,44 @@ +/** + * Internal dependencies + */ +import { getPageError } from '../get-page-error'; + +describe( 'getPageError', () => { + let originalPage; + + beforeEach( () => { + originalPage = global.page; + } ); + + afterEach( () => { + global.page = originalPage; + } ); + + it( 'resolves to null if there is no error', async () => { + global.page = { + content: () => 'Happy!', + }; + + expect( await getPageError() ).toBe( null ); + } ); + + it.each( [ + [ + 'PHP, HTML', + '<b>Notice</b>: Undefined property: WP_Block_Type_Registry::$x in <b>/var/www/html/wp-content/plugins/gutenberg/lib/blocks.php</b> on line <b>47</b>', + ], + [ + 'PHP, Plaintext', + 'Notice: Undefined property: WP_Block_Type_Registry::$x in /var/www/html/wp-content/plugins/gutenberg/lib/blocks.php on line 47', + ], + ] )( + 'resolves to the error message if there is an error (%s)', + async ( _variant, error ) => { + global.page = { + content: () => error, + }; + + expect( await getPageError() ).toBe( error ); + } + ); +} ); diff --git a/packages/e2e-test-utils/src/transform-block-to.js b/packages/e2e-test-utils/src/transform-block-to.js index f3aa8f97b2f523..8de1debe491a83 100644 --- a/packages/e2e-test-utils/src/transform-block-to.js +++ b/packages/e2e-test-utils/src/transform-block-to.js @@ -12,9 +12,10 @@ export async function transformBlockTo( name ) { await switcherToggle.click(); // Find the block button option within the switcher popover. - const switcher = await page.$( '.block-editor-block-switcher__container' ); const insertButton = ( - await switcher.$x( `//button[.='${ name }']` ) + await page.$x( + `//*[contains(@class, "block-editor-block-switcher__popover")]//button[.='${ name }']` + ) )[ 0 ]; // Clicks may fail if the button is out of view. Assure it is before click. diff --git a/packages/e2e-test-utils/src/visit-admin-page.js b/packages/e2e-test-utils/src/visit-admin-page.js index ac74c4ce688182..8f4a6c7260d34a 100644 --- a/packages/e2e-test-utils/src/visit-admin-page.js +++ b/packages/e2e-test-utils/src/visit-admin-page.js @@ -9,6 +9,7 @@ import { join } from 'path'; import { createURL } from './create-url'; import { isCurrentURL } from './is-current-url'; import { loginUser } from './login-user'; +import { getPageError } from './get-page-error'; /** * Visits admin page; if user is not logged in then it logging in it first, then visits admin page. @@ -23,4 +24,9 @@ export async function visitAdminPage( adminPath, query ) { await loginUser(); await visitAdminPage( adminPath, query ); } + + const error = await getPageError(); + if ( error ) { + throw new Error( 'Unexpected error in page content: ' + error ); + } } diff --git a/packages/e2e-tests/config/performance-reporter.js b/packages/e2e-tests/config/performance-reporter.js index 03bb99795f848b..32ea362973ed1f 100644 --- a/packages/e2e-tests/config/performance-reporter.js +++ b/packages/e2e-tests/config/performance-reporter.js @@ -1,4 +1,5 @@ const { readFileSync, existsSync } = require( 'fs' ); +const chalk = require( 'chalk' ); function average( array ) { return array.reduce( ( a, b ) => a + b ) / array.length; @@ -9,6 +10,9 @@ function round( number, decimalPlaces = 2 ) { return Math.round( number * factor ) / factor; } +const title = chalk.bold; +const success = chalk.bold.green; + class PerformanceReporter { onRunComplete() { const path = __dirname + '/../specs/performance/results.json'; @@ -18,16 +22,46 @@ class PerformanceReporter { } const results = readFileSync( path, 'utf8' ); - const { load, domcontentloaded, type } = JSON.parse( results ); + const { load, domcontentloaded, type, focus } = JSON.parse( results ); + + if ( load && load.length ) { + // eslint-disable-next-line no-console + console.log( ` +${ title( 'Loading Time:' ) } +Average time to load: ${ success( round( average( load ) ) + 'ms' ) } +Average time to DOM content load: ${ success( + round( average( domcontentloaded ) ) + 'ms' + ) }` ); + } + + if ( type && type.length ) { + // eslint-disable-next-line no-console + console.log( ` +${ title( 'Typing Performance:' ) } +Average time to type character: ${ success( round( average( type ) ) + 'ms' ) } +Slowest time to type character: ${ success( + round( Math.max( ...type ) ) + 'ms' + ) } +Fastest time to type character: ${ success( + round( Math.min( ...type ) ) + 'ms' + ) }` ); + } + + if ( focus && focus.length ) { + // eslint-disable-next-line no-console + console.log( ` +${ title( 'Block Selection Performance:' ) } +Average time to select a block: ${ success( round( average( focus ) ) + 'ms' ) } +Slowest time to select a block: ${ success( + round( Math.max( ...focus ) ) + 'ms' + ) } +Fastest time to select a block: ${ success( + round( Math.min( ...focus ) ) + 'ms' + ) }` ); + } // eslint-disable-next-line no-console - console.log( ` -Average time to load: ${ round( average( load ) ) }ms -Average time to DOM content load: ${ round( average( domcontentloaded ) ) }ms -Average time to type character: ${ round( average( type ) ) }ms -Slowest time to type character: ${ round( Math.max( ...type ) ) }ms -Fastest time to type character: ${ round( Math.min( ...type ) ) }ms - ` ); + console.log( '' ); } } diff --git a/packages/e2e-tests/config/setup-test-framework.js b/packages/e2e-tests/config/setup-test-framework.js index d4f547a7190cc4..8a78279730d317 100644 --- a/packages/e2e-tests/config/setup-test-framework.js +++ b/packages/e2e-tests/config/setup-test-framework.js @@ -16,6 +16,7 @@ import { switchUserToTest, visitAdminPage, } from '@wordpress/e2e-test-utils'; +import { addQueryArgs } from '@wordpress/url'; /** * Timeout, in seconds, that the test should be allowed to run. @@ -69,12 +70,17 @@ async function setupBrowser() { /** * Navigates to the post listing screen and bulk-trashes any posts which exist. * + * @param {string} postType - String slug for type of post to trash. + * * @return {Promise} Promise resolving once posts have been trashed. */ -async function trashExistingPosts() { +export async function trashExistingPosts( postType = 'post' ) { await switchUserToAdmin(); // Visit `/wp-admin/edit.php` so we can see a list of posts and delete them. - await visitAdminPage( 'edit.php' ); + const query = addQueryArgs( '', { + post_type: postType, + } ).slice( 1 ); + await visitAdminPage( 'edit.php', query ); // If this selector doesn't exist there are no posts for us to delete. const bulkSelector = await page.$( '#bulk-action-selector-top' ); @@ -228,6 +234,7 @@ async function runAxeTestsForBlockEditor() { 'dlitem', 'duplicate-id', 'label', + 'landmark-one-main', 'link-name', 'listitem', 'region', diff --git a/packages/e2e-tests/fixtures/blocks/core__button__center.serialized.html b/packages/e2e-tests/fixtures/blocks/core__button__center.serialized.html deleted file mode 100644 index 3d88c7ec1a551a..00000000000000 --- a/packages/e2e-tests/fixtures/blocks/core__button__center.serialized.html +++ /dev/null @@ -1,3 +0,0 @@ -<!-- wp:button {"align":"center"} --> -<div class="wp-block-button aligncenter"><a class="wp-block-button__link" href="https://github.com/WordPress/gutenberg">Help build Gutenberg</a></div> -<!-- /wp:button --> diff --git a/packages/e2e-tests/fixtures/blocks/core__button__center.html b/packages/e2e-tests/fixtures/blocks/core__button__center__deprecated.html similarity index 100% rename from packages/e2e-tests/fixtures/blocks/core__button__center.html rename to packages/e2e-tests/fixtures/blocks/core__button__center__deprecated.html diff --git a/packages/e2e-tests/fixtures/blocks/core__button__center.json b/packages/e2e-tests/fixtures/blocks/core__button__center__deprecated.json similarity index 100% rename from packages/e2e-tests/fixtures/blocks/core__button__center.json rename to packages/e2e-tests/fixtures/blocks/core__button__center__deprecated.json diff --git a/packages/e2e-tests/fixtures/blocks/core__button__center.parsed.json b/packages/e2e-tests/fixtures/blocks/core__button__center__deprecated.parsed.json similarity index 100% rename from packages/e2e-tests/fixtures/blocks/core__button__center.parsed.json rename to packages/e2e-tests/fixtures/blocks/core__button__center__deprecated.parsed.json diff --git a/packages/e2e-tests/fixtures/blocks/core__button__center__deprecated.serialized.html b/packages/e2e-tests/fixtures/blocks/core__button__center__deprecated.serialized.html new file mode 100644 index 00000000000000..5fee004c30ddd6 --- /dev/null +++ b/packages/e2e-tests/fixtures/blocks/core__button__center__deprecated.serialized.html @@ -0,0 +1,3 @@ +<!-- wp:button {"align":"center"} --> +<a class="wp-block-button aligncenter wp-block-button__link" href="https://github.com/WordPress/gutenberg">Help build Gutenberg</a> +<!-- /wp:button --> diff --git a/packages/e2e-tests/fixtures/blocks/core__button__squared.html b/packages/e2e-tests/fixtures/blocks/core__button__squared.html index ddf0e54bc46cd3..d7a2b6f5f95908 100644 --- a/packages/e2e-tests/fixtures/blocks/core__button__squared.html +++ b/packages/e2e-tests/fixtures/blocks/core__button__squared.html @@ -1,3 +1,3 @@ -<!-- wp:button {"customBackgroundColor":"#aa5a20","customTextColor":"#1b9b6c","className":"is-style-squared"} --> -<div class="wp-block-button is-style-squared"><a class="wp-block-button__link has-text-color has-background" style="background-color:#aa5a20;color:#1b9b6c">My button</a></div> +<!-- wp:button {"borderRadius":0,"align":"none","style":{"color":{"text":"#1b9b6c","background":"#aa5a20"}}} --> +<a class="wp-block-button wp-block-button__link no-border-radius has-text-color has-background" style="background-color:#aa5a20;color:#1b9b6c">My button</a> <!-- /wp:button --> diff --git a/packages/e2e-tests/fixtures/blocks/core__button__squared.json b/packages/e2e-tests/fixtures/blocks/core__button__squared.json index aa0b51793a6465..f3aa8241d516f0 100644 --- a/packages/e2e-tests/fixtures/blocks/core__button__squared.json +++ b/packages/e2e-tests/fixtures/blocks/core__button__squared.json @@ -5,12 +5,16 @@ "isValid": true, "attributes": { "text": "My button", - "align": "none", - "customBackgroundColor": "#aa5a20", - "customTextColor": "#1b9b6c", + "align": "none", + "style": { + "color": { + "background": "#aa5a20", + "text": "#1b9b6c" + } + }, "borderRadius": 0 }, "innerBlocks": [], - "originalContent": "<div class=\"wp-block-button is-style-squared\"><a class=\"wp-block-button__link has-text-color has-background\" style=\"background-color:#aa5a20;color:#1b9b6c\">My button</a></div>" + "originalContent": "<a class=\"wp-block-button wp-block-button__link no-border-radius has-text-color has-background\" style=\"background-color:#aa5a20;color:#1b9b6c\">My button</a>" } ] diff --git a/packages/e2e-tests/fixtures/blocks/core__button__squared.parsed.json b/packages/e2e-tests/fixtures/blocks/core__button__squared.parsed.json index 61facd925b7497..dc1ea8f2ca3470 100644 --- a/packages/e2e-tests/fixtures/blocks/core__button__squared.parsed.json +++ b/packages/e2e-tests/fixtures/blocks/core__button__squared.parsed.json @@ -2,14 +2,19 @@ { "blockName": "core/button", "attrs": { - "customBackgroundColor": "#aa5a20", - "customTextColor": "#1b9b6c", - "className": "is-style-squared" + "align": "none", + "borderRadius": 0, + "style": { + "color": { + "background": "#aa5a20", + "text": "#1b9b6c" + } + } }, "innerBlocks": [], - "innerHTML": "\n<div class=\"wp-block-button is-style-squared\"><a class=\"wp-block-button__link has-text-color has-background\" style=\"background-color:#aa5a20;color:#1b9b6c\">My button</a></div>\n", + "innerHTML": "\n<a class=\"wp-block-button wp-block-button__link no-border-radius has-text-color has-background\" style=\"background-color:#aa5a20;color:#1b9b6c\">My button</a>\n", "innerContent": [ - "\n<div class=\"wp-block-button is-style-squared\"><a class=\"wp-block-button__link has-text-color has-background\" style=\"background-color:#aa5a20;color:#1b9b6c\">My button</a></div>\n" + "\n<a class=\"wp-block-button wp-block-button__link no-border-radius has-text-color has-background\" style=\"background-color:#aa5a20;color:#1b9b6c\">My button</a>\n" ] }, { diff --git a/packages/e2e-tests/fixtures/blocks/core__button__squared.serialized.html b/packages/e2e-tests/fixtures/blocks/core__button__squared.serialized.html index 3d492c6ee0fe81..d7a2b6f5f95908 100644 --- a/packages/e2e-tests/fixtures/blocks/core__button__squared.serialized.html +++ b/packages/e2e-tests/fixtures/blocks/core__button__squared.serialized.html @@ -1,3 +1,3 @@ -<!-- wp:button {"customBackgroundColor":"#aa5a20","customTextColor":"#1b9b6c","borderRadius":0,"align":"none"} --> -<div class="wp-block-button"><a class="wp-block-button__link has-text-color has-background no-border-radius" style="background-color:#aa5a20;color:#1b9b6c">My button</a></div> +<!-- wp:button {"borderRadius":0,"align":"none","style":{"color":{"text":"#1b9b6c","background":"#aa5a20"}}} --> +<a class="wp-block-button wp-block-button__link no-border-radius has-text-color has-background" style="background-color:#aa5a20;color:#1b9b6c">My button</a> <!-- /wp:button --> diff --git a/packages/e2e-tests/fixtures/blocks/core__buttons.html b/packages/e2e-tests/fixtures/blocks/core__buttons.html index e70af7acc72ad4..02f5487560cee4 100644 --- a/packages/e2e-tests/fixtures/blocks/core__buttons.html +++ b/packages/e2e-tests/fixtures/blocks/core__buttons.html @@ -1,11 +1,11 @@ <!-- wp:buttons --> <div class="wp-block-buttons"> <!-- wp:button --> - <div class="wp-block-button"><a class="wp-block-button__link">My button 1</a></div> + <a class="wp-block-button wp-block-button__link">My button 1</a> <!-- /wp:button --> <!-- wp:button --> - <div class="wp-block-button"><a class="wp-block-button__link">My button 2</a></div> + <a class="wp-block-button wp-block-button__link">My button 2</a> <!-- /wp:button --> </div> <!-- /wp:buttons --> diff --git a/packages/e2e-tests/fixtures/blocks/core__buttons.json b/packages/e2e-tests/fixtures/blocks/core__buttons.json index 044daeb82101ac..d77d9752de37b0 100644 --- a/packages/e2e-tests/fixtures/blocks/core__buttons.json +++ b/packages/e2e-tests/fixtures/blocks/core__buttons.json @@ -13,7 +13,7 @@ "text": "My button 1" }, "innerBlocks": [], - "originalContent": "<div class=\"wp-block-button\"><a class=\"wp-block-button__link\">My button 1</a></div>" + "originalContent": "<a class=\"wp-block-button wp-block-button__link\">My button 1</a>" }, { "clientId": "_clientId_1", @@ -23,7 +23,7 @@ "text": "My button 2" }, "innerBlocks": [], - "originalContent": "<div class=\"wp-block-button\"><a class=\"wp-block-button__link\">My button 2</a></div>" + "originalContent": "<a class=\"wp-block-button wp-block-button__link\">My button 2</a>" } ], "originalContent": "<div class=\"wp-block-buttons\">\n\t\n\n\t\n</div>" diff --git a/packages/e2e-tests/fixtures/blocks/core__buttons.parsed.json b/packages/e2e-tests/fixtures/blocks/core__buttons.parsed.json index b96b1f50db1fc9..ee9dd97313a48b 100644 --- a/packages/e2e-tests/fixtures/blocks/core__buttons.parsed.json +++ b/packages/e2e-tests/fixtures/blocks/core__buttons.parsed.json @@ -7,18 +7,18 @@ "blockName": "core/button", "attrs": {}, "innerBlocks": [], - "innerHTML": "\n\t<div class=\"wp-block-button\"><a class=\"wp-block-button__link\">My button 1</a></div>\n\t", + "innerHTML": "\n\t<a class=\"wp-block-button wp-block-button__link\">My button 1</a>\n\t", "innerContent": [ - "\n\t<div class=\"wp-block-button\"><a class=\"wp-block-button__link\">My button 1</a></div>\n\t" + "\n\t<a class=\"wp-block-button wp-block-button__link\">My button 1</a>\n\t" ] }, { "blockName": "core/button", "attrs": {}, "innerBlocks": [], - "innerHTML": "\n\t<div class=\"wp-block-button\"><a class=\"wp-block-button__link\">My button 2</a></div>\n\t", + "innerHTML": "\n\t<a class=\"wp-block-button wp-block-button__link\">My button 2</a>\n\t", "innerContent": [ - "\n\t<div class=\"wp-block-button\"><a class=\"wp-block-button__link\">My button 2</a></div>\n\t" + "\n\t<a class=\"wp-block-button wp-block-button__link\">My button 2</a>\n\t" ] } ], diff --git a/packages/e2e-tests/fixtures/blocks/core__buttons.serialized.html b/packages/e2e-tests/fixtures/blocks/core__buttons.serialized.html index baf0a0226c066c..18eb4b31eda593 100644 --- a/packages/e2e-tests/fixtures/blocks/core__buttons.serialized.html +++ b/packages/e2e-tests/fixtures/blocks/core__buttons.serialized.html @@ -1,9 +1,9 @@ <!-- wp:buttons --> <div class="wp-block-buttons"><!-- wp:button --> -<div class="wp-block-button"><a class="wp-block-button__link">My button 1</a></div> +<a class="wp-block-button wp-block-button__link">My button 1</a> <!-- /wp:button --> <!-- wp:button --> -<div class="wp-block-button"><a class="wp-block-button__link">My button 2</a></div> +<a class="wp-block-button wp-block-button__link">My button 2</a> <!-- /wp:button --></div> <!-- /wp:buttons --> diff --git a/packages/e2e-tests/fixtures/blocks/core__columns.serialized.html b/packages/e2e-tests/fixtures/blocks/core__columns.serialized.html index 664beb08154a7f..2b95373d1a7b83 100644 --- a/packages/e2e-tests/fixtures/blocks/core__columns.serialized.html +++ b/packages/e2e-tests/fixtures/blocks/core__columns.serialized.html @@ -1,5 +1,5 @@ <!-- wp:columns {"backgroundColor":"secondary"} --> -<div class="wp-block-columns has-background has-secondary-background-color"><!-- wp:column --> +<div class="wp-block-columns has-secondary-background-color has-background"><!-- wp:column --> <div class="wp-block-column"><!-- wp:paragraph --> <p>Column One, Paragraph One</p> <!-- /wp:paragraph --> diff --git a/packages/e2e-tests/fixtures/blocks/core__group.html b/packages/e2e-tests/fixtures/blocks/core__group.html index 09fd95cfc9d5a4..e5df0f2fce926a 100644 --- a/packages/e2e-tests/fixtures/blocks/core__group.html +++ b/packages/e2e-tests/fixtures/blocks/core__group.html @@ -1,4 +1,4 @@ -<!-- wp:group {"backgroundColor":"secondary","align":"full"} --> +<!-- wp:group {"align":"full","backgroundColor":"secondary"} --> <div class="wp-block-group alignfull has-secondary-background-color has-background"> <div class="wp-block-group__inner-container"> <!-- wp:paragraph --> diff --git a/packages/e2e-tests/fixtures/blocks/core__group.json b/packages/e2e-tests/fixtures/blocks/core__group.json index 71d94f926dcccf..526a8d70fbcdfa 100644 --- a/packages/e2e-tests/fixtures/blocks/core__group.json +++ b/packages/e2e-tests/fixtures/blocks/core__group.json @@ -4,8 +4,9 @@ "name": "core/group", "isValid": true, "attributes": { - "backgroundColor": "secondary", - "align": "full" + "tagName": "div", + "align": "full", + "backgroundColor": "secondary" }, "innerBlocks": [ { diff --git a/packages/e2e-tests/fixtures/blocks/core__group.parsed.json b/packages/e2e-tests/fixtures/blocks/core__group.parsed.json index bf2b50feb5fd1f..ba86ac5a02d6bd 100644 --- a/packages/e2e-tests/fixtures/blocks/core__group.parsed.json +++ b/packages/e2e-tests/fixtures/blocks/core__group.parsed.json @@ -2,8 +2,8 @@ { "blockName": "core/group", "attrs": { - "backgroundColor": "secondary", - "align": "full" + "align": "full", + "backgroundColor": "secondary" }, "innerBlocks": [ { diff --git a/packages/e2e-tests/fixtures/blocks/core__group.serialized.html b/packages/e2e-tests/fixtures/blocks/core__group.serialized.html index 2c398b530dedc5..8ac236255f9f61 100644 --- a/packages/e2e-tests/fixtures/blocks/core__group.serialized.html +++ b/packages/e2e-tests/fixtures/blocks/core__group.serialized.html @@ -1,4 +1,4 @@ -<!-- wp:group {"backgroundColor":"secondary","align":"full"} --> +<!-- wp:group {"align":"full","backgroundColor":"secondary"} --> <div class="wp-block-group alignfull has-secondary-background-color has-background"><div class="wp-block-group__inner-container"><!-- wp:paragraph --> <p>This is a group block.</p> <!-- /wp:paragraph --> diff --git a/packages/e2e-tests/fixtures/blocks/core__group__deprecated-2.json b/packages/e2e-tests/fixtures/blocks/core__group__deprecated-2.json index 38addc059eec30..7bfd9dafac7069 100644 --- a/packages/e2e-tests/fixtures/blocks/core__group__deprecated-2.json +++ b/packages/e2e-tests/fixtures/blocks/core__group__deprecated-2.json @@ -4,7 +4,8 @@ "name": "core/group", "isValid": true, "attributes": { - "textColor": "accent" + "textColor": "accent", + "tagName": "div" }, "innerBlocks": [ { diff --git a/packages/e2e-tests/fixtures/blocks/core__group__deprecated.html b/packages/e2e-tests/fixtures/blocks/core__group__deprecated.html index bd111993515f16..9b71121607e437 100644 --- a/packages/e2e-tests/fixtures/blocks/core__group__deprecated.html +++ b/packages/e2e-tests/fixtures/blocks/core__group__deprecated.html @@ -1,4 +1,4 @@ -<!-- wp:group {"backgroundColor":"lighter-blue","align":"full"} --> +<!-- wp:group {"align":"full","backgroundColor":"lighter-blue"} --> <div class="wp-block-group alignfull has-lighter-blue-background-color has-background" id="test-id"> <!-- wp:paragraph --> <p>test</p> diff --git a/packages/e2e-tests/fixtures/blocks/core__group__deprecated.json b/packages/e2e-tests/fixtures/blocks/core__group__deprecated.json index c86392f55adb97..7f1f51c3644e40 100644 --- a/packages/e2e-tests/fixtures/blocks/core__group__deprecated.json +++ b/packages/e2e-tests/fixtures/blocks/core__group__deprecated.json @@ -6,7 +6,8 @@ "attributes": { "backgroundColor": "lighter-blue", "align": "full", - "anchor": "test-id" + "anchor": "test-id", + "tagName": "div" }, "innerBlocks": [ { diff --git a/packages/e2e-tests/fixtures/blocks/core__group__deprecated.parsed.json b/packages/e2e-tests/fixtures/blocks/core__group__deprecated.parsed.json index 20116913b718f1..09778708d0b9e3 100644 --- a/packages/e2e-tests/fixtures/blocks/core__group__deprecated.parsed.json +++ b/packages/e2e-tests/fixtures/blocks/core__group__deprecated.parsed.json @@ -2,8 +2,8 @@ { "blockName": "core/group", "attrs": { - "backgroundColor": "lighter-blue", - "align": "full" + "align": "full", + "backgroundColor": "lighter-blue" }, "innerBlocks": [ { diff --git a/packages/e2e-tests/fixtures/blocks/core__group__deprecated.serialized.html b/packages/e2e-tests/fixtures/blocks/core__group__deprecated.serialized.html index 891c48e13ef040..b9f1dc3ba37e12 100644 --- a/packages/e2e-tests/fixtures/blocks/core__group__deprecated.serialized.html +++ b/packages/e2e-tests/fixtures/blocks/core__group__deprecated.serialized.html @@ -1,4 +1,4 @@ -<!-- wp:group {"backgroundColor":"lighter-blue","align":"full"} --> +<!-- wp:group {"align":"full","backgroundColor":"lighter-blue"} --> <div class="wp-block-group alignfull has-lighter-blue-background-color has-background" id="test-id"><div class="wp-block-group__inner-container"><!-- wp:paragraph --> <p>test</p> <!-- /wp:paragraph --></div></div> diff --git a/packages/e2e-tests/fixtures/blocks/core__heading__deprecated-3.json b/packages/e2e-tests/fixtures/blocks/core__heading__deprecated-3.json index ba5b3079e888c4..d4d93c52448969 100644 --- a/packages/e2e-tests/fixtures/blocks/core__heading__deprecated-3.json +++ b/packages/e2e-tests/fixtures/blocks/core__heading__deprecated-3.json @@ -6,7 +6,11 @@ "attributes": { "content": "Text", "level": 2, - "customTextColor": "#268ebb" + "style": { + "color": { + "text": "#268ebb" + } + } }, "innerBlocks": [], "originalContent": "<h2 style=\"color:#268ebb\">Text</h2>" diff --git a/packages/e2e-tests/fixtures/blocks/core__heading__deprecated-3.serialized.html b/packages/e2e-tests/fixtures/blocks/core__heading__deprecated-3.serialized.html index 7efa248386cefd..c2c4470e500f1e 100644 --- a/packages/e2e-tests/fixtures/blocks/core__heading__deprecated-3.serialized.html +++ b/packages/e2e-tests/fixtures/blocks/core__heading__deprecated-3.serialized.html @@ -1,3 +1,3 @@ -<!-- wp:heading {"customTextColor":"#268ebb"} --> +<!-- wp:heading {"style":{"color":{"text":"#268ebb"}}} --> <h2 class="has-text-color" style="color:#268ebb">Text</h2> <!-- /wp:heading --> diff --git a/packages/e2e-tests/package.json b/packages/e2e-tests/package.json index 6d0310cb4f428b..26f21d0e9664f8 100644 --- a/packages/e2e-tests/package.json +++ b/packages/e2e-tests/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/e2e-tests", - "version": "1.12.7", + "version": "1.14.1", "description": "End-To-End (E2E) tests for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -27,9 +27,10 @@ "@wordpress/jest-puppeteer-axe": "file:../jest-puppeteer-axe", "@wordpress/scripts": "file:../scripts", "@wordpress/url": "file:../url", - "expect-puppeteer": "^4.3.0", + "chalk": "^4.0.0", + "expect-puppeteer": "^4.4.0", "lodash": "^4.17.15", - "uuid": "^3.3.2" + "uuid": "^7.0.2" }, "peerDependencies": { "jest": ">=24", diff --git a/packages/e2e-tests/plugins/block-context.php b/packages/e2e-tests/plugins/block-context.php new file mode 100644 index 00000000000000..13db6436630d30 --- /dev/null +++ b/packages/e2e-tests/plugins/block-context.php @@ -0,0 +1,63 @@ +<?php +/** + * Plugin Name: Gutenberg Test Block Context + * Plugin URI: https://github.com/WordPress/gutenberg + * Author: Gutenberg Team + * + * @package gutenberg-test-block-context + */ + +/** + * Enqueues a custom script for the plugin. + */ +function gutenberg_test_enqueue_block_context_script() { + wp_enqueue_script( + 'gutenberg-test-block-context', + plugins_url( 'block-context/index.js', __FILE__ ), + array( + 'wp-block-editor', + 'wp-blocks', + 'wp-element', + ), + filemtime( plugin_dir_path( __FILE__ ) . 'block-context/index.js' ), + true + ); +} +add_action( 'init', 'gutenberg_test_enqueue_block_context_script' ); + +/** + * Registers plugin test context blocks. + */ +function gutenberg_test_register_context_blocks() { + register_block_type( + 'gutenberg/test-context-provider', + array( + 'attributes' => array( + 'recordId' => array( + 'type' => 'number', + 'default' => 0, + ), + ), + 'providesContext' => array( + 'gutenberg/recordId' => 'recordId', + ), + ) + ); + + register_block_type( + 'gutenberg/test-context-consumer', + array( + 'context' => array( 'gutenberg/recordId' ), + 'render_callback' => function( $block ) { + $record_id = $block->context['gutenberg/recordId']; + + if ( ! is_int( $record_id ) ) { + throw new Exception( 'Expected numeric recordId' ); + } + + return 'The record ID is: ' . filter_var( $record_id, FILTER_VALIDATE_INT ); + }, + ) + ); +} +add_action( 'init', 'gutenberg_test_register_context_blocks' ); diff --git a/packages/e2e-tests/plugins/block-context/index.js b/packages/e2e-tests/plugins/block-context/index.js new file mode 100644 index 00000000000000..2ccd6c6059ce99 --- /dev/null +++ b/packages/e2e-tests/plugins/block-context/index.js @@ -0,0 +1,60 @@ +( function() { + const { createElement: el, Fragment } = wp.element; + const { registerBlockType } = wp.blocks; + const { InnerBlocks } = wp.blockEditor; + + registerBlockType( 'gutenberg/test-context-provider', { + title: 'Test Context Provider', + + // TODO: While redundant with server-side registration, it's required + // to assign this value since it is not picked in the implementation of + // `get_block_editor_server_block_settings`. + providesContext: { + 'gutenberg/recordId': 'recordId', + }, + + category: 'common', + + edit( { attributes, setAttributes } ) { + return el( + Fragment, + null, + el( 'input', { + value: attributes.recordId, + onChange( event ) { + setAttributes( { + recordId: Number( event.currentTarget.value ), + } ); + }, + } ), + el( InnerBlocks, { + template: [ [ 'gutenberg/test-context-consumer', {} ] ], + templateLock: 'all', + } ) + ); + }, + + save() { + return el( InnerBlocks.Content ); + }, + } ); + + registerBlockType( 'gutenberg/test-context-consumer', { + title: 'Test Context Consumer', + + // TODO: While redundant with server-side registration, it's required + // to assign this value since it is not picked in the implementation of + // `get_block_editor_server_block_settings`. + context: [ 'gutenberg/recordId' ], + + category: 'common', + + edit( { context } ) { + return 'The record ID is: ' + context[ 'gutenberg/recordId' ]; + }, + + save() { + return null; + }, + } ); +} )(); diff --git a/packages/e2e-tests/plugins/inner-blocks-allowed-blocks/index.js b/packages/e2e-tests/plugins/inner-blocks-allowed-blocks/index.js index f6f61c27d5c82c..f85721b0d15e78 100644 --- a/packages/e2e-tests/plugins/inner-blocks-allowed-blocks/index.js +++ b/packages/e2e-tests/plugins/inner-blocks-allowed-blocks/index.js @@ -4,19 +4,20 @@ const { createElement: el } = wp.element; const { InnerBlocks } = wp.blockEditor; const __ = wp.i18n.__; - const divProps = { className: 'product', style: { outline: '1px solid gray', padding: 5 } }; + const divProps = { + className: 'product', + style: { outline: '1px solid gray', padding: 5 }, + }; const template = [ [ 'core/image' ], [ 'core/paragraph', { placeholder: __( 'Add a description' ) } ], - [ 'core/quote' ] + [ 'core/quote' ], ]; const allowedBlocksWhenSingleEmptyChild = [ 'core/image', 'core/list' ]; const allowedBlocksWhenMultipleChildren = [ 'core/gallery', 'core/video' ]; const save = function() { - return el( 'div', divProps, - el( InnerBlocks.Content ) - ); + return el( 'div', divProps, el( InnerBlocks.Content ) ); }; registerBlockType( 'test/allowed-blocks-unset', { title: 'Allowed Blocks Unset', @@ -24,9 +25,7 @@ category: 'common', edit() { - return el( 'div', divProps, - el( InnerBlocks, { template } ) - ); + return el( 'div', divProps, el( InnerBlocks, { template } ) ); }, save, @@ -38,20 +37,19 @@ category: 'common', edit() { - return el( 'div', divProps, - el( - InnerBlocks, - { - template, - allowedBlocks: [ - 'core/button', - 'core/gallery', - 'core/list', - 'core/media-text', - 'core/quote', - ], - } - ) + return el( + 'div', + divProps, + el( InnerBlocks, { + template, + allowedBlocks: [ + 'core/button', + 'core/gallery', + 'core/list', + 'core/media-text', + 'core/quote', + ], + } ) ); }, @@ -69,19 +67,21 @@ numberOfChildren: getBlockOrder( ownProps.clientId ).length, }; } )( function( props ) { - return el( 'div', divProps, - el( - InnerBlocks, - { - allowedBlocks: props.numberOfChildren < 2 ? - allowedBlocksWhenSingleEmptyChild : - allowedBlocksWhenMultipleChildren, - } - ) + return el( + 'div', + { + ...divProps, + 'data-number-of-children': props.numberOfChildren, + }, + el( InnerBlocks, { + allowedBlocks: + props.numberOfChildren < 2 + ? allowedBlocksWhenSingleEmptyChild + : allowedBlocksWhenMultipleChildren, + } ) ); } ), save, } ); - } )(); diff --git a/packages/e2e-tests/plugins/plugins-api/sidebar.js b/packages/e2e-tests/plugins/plugins-api/sidebar.js index 5ce92bcd4e09a2..5258cd01179d5d 100644 --- a/packages/e2e-tests/plugins/plugins-api/sidebar.js +++ b/packages/e2e-tests/plugins/plugins-api/sidebar.js @@ -18,7 +18,7 @@ function SidebarContents( props ) { return el( PanelBody, - {}, + { className: 'sidebar-title-plugin-panel' }, el( PanelRow, {}, diff --git a/packages/e2e-tests/specs/editor/blocks/__snapshots__/buttons.test.js.snap b/packages/e2e-tests/specs/editor/blocks/__snapshots__/buttons.test.js.snap index 66f803ddcf139f..08a92e1fd8820f 100644 --- a/packages/e2e-tests/specs/editor/blocks/__snapshots__/buttons.test.js.snap +++ b/packages/e2e-tests/specs/editor/blocks/__snapshots__/buttons.test.js.snap @@ -3,7 +3,7 @@ exports[`Buttons can jump to the link editor using the keyboard shortcut 1`] = ` "<!-- wp:buttons --> <div class=\\"wp-block-buttons\\"><!-- wp:button --> -<div class=\\"wp-block-button\\"><a class=\\"wp-block-button__link\\" href=\\"https://www.wordpress.org/\\">WordPress</a></div> +<a class=\\"wp-block-button wp-block-button__link\\" href=\\"https://www.wordpress.org/\\">WordPress</a> <!-- /wp:button --></div> <!-- /wp:buttons -->" `; @@ -11,7 +11,7 @@ exports[`Buttons can jump to the link editor using the keyboard shortcut 1`] = ` exports[`Buttons dismisses link editor when escape is pressed 1`] = ` "<!-- wp:buttons --> <div class=\\"wp-block-buttons\\"><!-- wp:button --> -<div class=\\"wp-block-button\\"><a class=\\"wp-block-button__link\\">WordPress</a></div> +<a class=\\"wp-block-button wp-block-button__link\\">WordPress</a> <!-- /wp:button --></div> <!-- /wp:buttons -->" `; @@ -19,7 +19,7 @@ exports[`Buttons dismisses link editor when escape is pressed 1`] = ` exports[`Buttons has focus on button content 1`] = ` "<!-- wp:buttons --> <div class=\\"wp-block-buttons\\"><!-- wp:button --> -<div class=\\"wp-block-button\\"><a class=\\"wp-block-button__link\\">Content</a></div> +<a class=\\"wp-block-button wp-block-button__link\\">Content</a> <!-- /wp:button --></div> <!-- /wp:buttons -->" `; diff --git a/packages/e2e-tests/specs/editor/blocks/__snapshots__/heading.test.js.snap b/packages/e2e-tests/specs/editor/blocks/__snapshots__/heading.test.js.snap index d36b3e658b5f84..c8edb2f56cf352 100644 --- a/packages/e2e-tests/specs/editor/blocks/__snapshots__/heading.test.js.snap +++ b/packages/e2e-tests/specs/editor/blocks/__snapshots__/heading.test.js.snap @@ -13,7 +13,7 @@ exports[`Heading can be created by prefixing number sign and a space 1`] = ` `; exports[`Heading it should correctly apply custom colors 1`] = ` -"<!-- wp:heading {\\"level\\":3,\\"customTextColor\\":\\"#7700ff\\"} --> +"<!-- wp:heading {\\"level\\":3,\\"style\\":{\\"color\\":{\\"text\\":\\"#7700ff\\"}}} --> <h3 class=\\"has-text-color\\" style=\\"color:#7700ff\\">Heading</h3> <!-- /wp:heading -->" `; diff --git a/packages/e2e-tests/specs/editor/blocks/classic.test.js b/packages/e2e-tests/specs/editor/blocks/classic.test.js index b8295c64d53df1..2e2f1274878166 100644 --- a/packages/e2e-tests/specs/editor/blocks/classic.test.js +++ b/packages/e2e-tests/specs/editor/blocks/classic.test.js @@ -4,7 +4,7 @@ import path from 'path'; import fs from 'fs'; import os from 'os'; -import uuid from 'uuid/v4'; +import { v4 as uuid } from 'uuid'; /** * WordPress dependencies diff --git a/packages/e2e-tests/specs/editor/blocks/columns.test.js b/packages/e2e-tests/specs/editor/blocks/columns.test.js index 6255f6c5c5ac8d..294c2de3be44f7 100644 --- a/packages/e2e-tests/specs/editor/blocks/columns.test.js +++ b/packages/e2e-tests/specs/editor/blocks/columns.test.js @@ -5,8 +5,8 @@ import { createNewPost, getAllBlockInserterItemTitles, insertBlock, - openAllBlockInserterCategories, openGlobalBlockInserter, + closeGlobalBlockInserter, } from '@wordpress/e2e-test-utils'; describe( 'Columns', () => { @@ -16,6 +16,7 @@ describe( 'Columns', () => { it( 'restricts all blocks inside the columns block', async () => { await insertBlock( 'Columns' ); + await closeGlobalBlockInserter(); await page.click( '[aria-label="Two columns; equal split"]' ); await page.click( '[aria-label="Block navigation"]' ); const columnBlockMenuItem = ( @@ -25,7 +26,6 @@ describe( 'Columns', () => { )[ 0 ]; await columnBlockMenuItem.click(); await openGlobalBlockInserter(); - await openAllBlockInserterCategories(); expect( await getAllBlockInserterItemTitles() ).toHaveLength( 0 ); } ); } ); diff --git a/packages/e2e-tests/specs/editor/blocks/image.test.js b/packages/e2e-tests/specs/editor/blocks/image.test.js index 51c4987857898f..c98ac89daf14af 100644 --- a/packages/e2e-tests/specs/editor/blocks/image.test.js +++ b/packages/e2e-tests/specs/editor/blocks/image.test.js @@ -4,7 +4,7 @@ import path from 'path'; import fs from 'fs'; import os from 'os'; -import uuid from 'uuid/v4'; +import { v4 as uuid } from 'uuid'; /** * WordPress dependencies @@ -14,6 +14,7 @@ import { getEditedPostContent, createNewPost, clickButton, + openDocumentSettingsSidebar, } from '@wordpress/e2e-test-utils'; async function upload( selector ) { @@ -31,7 +32,9 @@ async function upload( selector ) { const tmpFileName = path.join( os.tmpdir(), filename + '.png' ); fs.copyFileSync( testImagePath, tmpFileName ); await inputElement.uploadFile( tmpFileName ); - await page.waitForSelector( '.wp-block-image img[src^="http"]' ); + await page.waitForSelector( + `.wp-block-image img[src$="${ filename }.png"]` + ); return filename; } @@ -59,6 +62,7 @@ describe( 'Image', () => { ); expect( await getEditedPostContent() ).toMatch( regex1 ); + await openDocumentSettingsSidebar(); await page.click( '[aria-label="Image Size"] button' ); const regex2 = new RegExp( diff --git a/packages/e2e-tests/specs/editor/blocks/table.test.js b/packages/e2e-tests/specs/editor/blocks/table.test.js index 680416980067d5..96bb008e613df3 100644 --- a/packages/e2e-tests/specs/editor/blocks/table.test.js +++ b/packages/e2e-tests/specs/editor/blocks/table.test.js @@ -12,6 +12,7 @@ import { createNewPost, getEditedPostContent, insertBlock, + openDocumentSettingsSidebar, } from '@wordpress/e2e-test-utils'; const createButtonLabel = 'Create Table'; @@ -99,6 +100,7 @@ describe( 'Table', () => { it( 'allows header and footer rows to be switched on and off', async () => { await insertBlock( 'Table' ); + await openDocumentSettingsSidebar(); const headerSwitchSelector = "//label[text()='Header section']"; const footerSwitchSelector = "//label[text()='Footer section']"; @@ -144,6 +146,7 @@ describe( 'Table', () => { it( 'allows adding and deleting columns across the table header, body and footer', async () => { await insertBlock( 'Table' ); + await openDocumentSettingsSidebar(); // Create the table. await clickButton( createButtonLabel ); @@ -217,6 +220,7 @@ describe( 'Table', () => { // Testing for regressions of https://github.com/WordPress/gutenberg/issues/14904. it( 'allows cells to be selected when the cell area outside of the RichText is clicked', async () => { await insertBlock( 'Table' ); + await openDocumentSettingsSidebar(); // Create the table. await clickButton( createButtonLabel ); diff --git a/packages/e2e-tests/specs/editor/plugins/__snapshots__/plugins-api.test.js.snap b/packages/e2e-tests/specs/editor/plugins/__snapshots__/plugins-api.test.js.snap index f823deeb3965f8..e30da101c25883 100644 --- a/packages/e2e-tests/specs/editor/plugins/__snapshots__/plugins-api.test.js.snap +++ b/packages/e2e-tests/specs/editor/plugins/__snapshots__/plugins-api.test.js.snap @@ -2,6 +2,6 @@ exports[`Using Plugins API Document Setting Custom Panel Should render a custom panel inside Document Setting sidebar 1`] = `"My Custom Panel"`; -exports[`Using Plugins API Sidebar Medium screen Should open plugins sidebar using More Menu item and render content 1`] = `"<div class=\\"components-panel__header edit-post-sidebar-header__small\\"><span class=\\"edit-post-sidebar-header__title\\">(no title)</span><button type=\\"button\\" class=\\"components-button has-icon\\" aria-label=\\"Close plugin\\"><svg width=\\"24\\" height=\\"24\\" xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 24 24\\" role=\\"img\\" aria-hidden=\\"true\\" focusable=\\"false\\"><path d=\\"M13 11.8l6.1-6.3-1-1-6.1 6.2-6.1-6.2-1 1 6.1 6.3-6.5 6.7 1 1 6.5-6.6 6.5 6.6 1-1z\\"></path></svg></button></div><div class=\\"components-panel__header edit-post-sidebar-header\\"><strong>Sidebar title plugin</strong><button type=\\"button\\" aria-pressed=\\"true\\" aria-expanded=\\"true\\" class=\\"components-button is-pressed has-icon\\" aria-label=\\"Unpin from toolbar\\"><svg width=\\"24\\" height=\\"24\\" xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"-2 -2 24 24\\" role=\\"img\\" aria-hidden=\\"true\\" focusable=\\"false\\"><path d=\\"M10 1l3 6 6 .75-4.12 4.62L16 19l-6-3-6 3 1.13-6.63L1 7.75 7 7z\\"></path></svg></button><button type=\\"button\\" class=\\"components-button has-icon\\" aria-label=\\"Close plugin\\"><svg width=\\"24\\" height=\\"24\\" xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 24 24\\" role=\\"img\\" aria-hidden=\\"true\\" focusable=\\"false\\"><path d=\\"M13 11.8l6.1-6.3-1-1-6.1 6.2-6.1-6.2-1 1 6.1 6.3-6.5 6.7 1 1 6.5-6.6 6.5 6.6 1-1z\\"></path></svg></button></div><div class=\\"components-panel\\"><div class=\\"components-panel__body is-opened\\"><div class=\\"components-panel__row\\"><label for=\\"title-plain-text\\">Title:</label><textarea class=\\"block-editor-plain-text\\" id=\\"title-plain-text\\" placeholder=\\"(no title)\\" rows=\\"1\\" style=\\"overflow: hidden; overflow-wrap: break-word; resize: none; height: 18px;\\"></textarea></div><div class=\\"components-panel__row\\"><button type=\\"button\\" class=\\"components-button is-primary\\">Reset</button></div></div></div>"`; +exports[`Using Plugins API Sidebar Medium screen Should open plugins sidebar using More Menu item and render content 1`] = `"<div class=\\"components-panel__header interface-complementary-area-header__small\\"><span class=\\"interface-complementary-area-header__small-title\\">(no title)</span><button type=\\"button\\" class=\\"components-button has-icon\\" aria-label=\\"Close plugin\\"><svg width=\\"24\\" height=\\"24\\" xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 24 24\\" role=\\"img\\" aria-hidden=\\"true\\" focusable=\\"false\\"><path d=\\"M13 11.8l6.1-6.3-1-1-6.1 6.2-6.1-6.2-1 1 6.1 6.3-6.5 6.7 1 1 6.5-6.6 6.5 6.6 1-1z\\"></path></svg></button></div><div class=\\"components-panel__header interface-complementary-area-header\\" tabindex=\\"-1\\"><strong>Sidebar title plugin</strong><button type=\\"button\\" aria-pressed=\\"true\\" aria-expanded=\\"true\\" class=\\"components-button interface-complementary-area__pin-unpin-item is-pressed has-icon\\" aria-label=\\"Unpin from toolbar\\"><svg width=\\"24\\" height=\\"24\\" xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"-2 -2 24 24\\" role=\\"img\\" aria-hidden=\\"true\\" focusable=\\"false\\"><path d=\\"M10 1l3 6 6 .75-4.12 4.62L16 19l-6-3-6 3 1.13-6.63L1 7.75 7 7z\\"></path></svg></button><button type=\\"button\\" class=\\"components-button has-icon\\" aria-label=\\"Close plugin\\"><svg width=\\"24\\" height=\\"24\\" xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 24 24\\" role=\\"img\\" aria-hidden=\\"true\\" focusable=\\"false\\"><path d=\\"M13 11.8l6.1-6.3-1-1-6.1 6.2-6.1-6.2-1 1 6.1 6.3-6.5 6.7 1 1 6.5-6.6 6.5 6.6 1-1z\\"></path></svg></button></div><div class=\\"components-panel\\"><div class=\\"components-panel__body sidebar-title-plugin-panel is-opened\\"><div class=\\"components-panel__row\\"><label for=\\"title-plain-text\\">Title:</label><textarea class=\\"block-editor-plain-text\\" id=\\"title-plain-text\\" placeholder=\\"(no title)\\" rows=\\"1\\" style=\\"overflow: hidden; overflow-wrap: break-word; resize: none; height: 18px;\\"></textarea></div><div class=\\"components-panel__row\\"><button type=\\"button\\" class=\\"components-button is-primary\\">Reset</button></div></div></div>"`; -exports[`Using Plugins API Sidebar Should open plugins sidebar using More Menu item and render content 1`] = `"<div class=\\"components-panel__header edit-post-sidebar-header__small\\"><span class=\\"edit-post-sidebar-header__title\\">(no title)</span><button type=\\"button\\" class=\\"components-button has-icon\\" aria-label=\\"Close plugin\\"><svg width=\\"24\\" height=\\"24\\" xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 24 24\\" role=\\"img\\" aria-hidden=\\"true\\" focusable=\\"false\\"><path d=\\"M13 11.8l6.1-6.3-1-1-6.1 6.2-6.1-6.2-1 1 6.1 6.3-6.5 6.7 1 1 6.5-6.6 6.5 6.6 1-1z\\"></path></svg></button></div><div class=\\"components-panel__header edit-post-sidebar-header\\"><strong>Sidebar title plugin</strong><button type=\\"button\\" aria-pressed=\\"true\\" aria-expanded=\\"true\\" class=\\"components-button is-pressed has-icon\\" aria-label=\\"Unpin from toolbar\\"><svg width=\\"24\\" height=\\"24\\" xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"-2 -2 24 24\\" role=\\"img\\" aria-hidden=\\"true\\" focusable=\\"false\\"><path d=\\"M10 1l3 6 6 .75-4.12 4.62L16 19l-6-3-6 3 1.13-6.63L1 7.75 7 7z\\"></path></svg></button><button type=\\"button\\" class=\\"components-button has-icon\\" aria-label=\\"Close plugin\\"><svg width=\\"24\\" height=\\"24\\" xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 24 24\\" role=\\"img\\" aria-hidden=\\"true\\" focusable=\\"false\\"><path d=\\"M13 11.8l6.1-6.3-1-1-6.1 6.2-6.1-6.2-1 1 6.1 6.3-6.5 6.7 1 1 6.5-6.6 6.5 6.6 1-1z\\"></path></svg></button></div><div class=\\"components-panel\\"><div class=\\"components-panel__body is-opened\\"><div class=\\"components-panel__row\\"><label for=\\"title-plain-text\\">Title:</label><textarea class=\\"block-editor-plain-text\\" id=\\"title-plain-text\\" placeholder=\\"(no title)\\" rows=\\"1\\" style=\\"overflow: hidden; overflow-wrap: break-word; resize: none; height: 18px;\\"></textarea></div><div class=\\"components-panel__row\\"><button type=\\"button\\" class=\\"components-button is-primary\\">Reset</button></div></div></div>"`; +exports[`Using Plugins API Sidebar Should open plugins sidebar using More Menu item and render content 1`] = `"<div class=\\"components-panel__header interface-complementary-area-header__small\\"><span class=\\"interface-complementary-area-header__small-title\\">(no title)</span><button type=\\"button\\" class=\\"components-button has-icon\\" aria-label=\\"Close plugin\\"><svg width=\\"24\\" height=\\"24\\" xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 24 24\\" role=\\"img\\" aria-hidden=\\"true\\" focusable=\\"false\\"><path d=\\"M13 11.8l6.1-6.3-1-1-6.1 6.2-6.1-6.2-1 1 6.1 6.3-6.5 6.7 1 1 6.5-6.6 6.5 6.6 1-1z\\"></path></svg></button></div><div class=\\"components-panel__header interface-complementary-area-header\\" tabindex=\\"-1\\"><strong>Sidebar title plugin</strong><button type=\\"button\\" aria-pressed=\\"true\\" aria-expanded=\\"true\\" class=\\"components-button interface-complementary-area__pin-unpin-item is-pressed has-icon\\" aria-label=\\"Unpin from toolbar\\"><svg width=\\"24\\" height=\\"24\\" xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"-2 -2 24 24\\" role=\\"img\\" aria-hidden=\\"true\\" focusable=\\"false\\"><path d=\\"M10 1l3 6 6 .75-4.12 4.62L16 19l-6-3-6 3 1.13-6.63L1 7.75 7 7z\\"></path></svg></button><button type=\\"button\\" class=\\"components-button has-icon\\" aria-label=\\"Close plugin\\"><svg width=\\"24\\" height=\\"24\\" xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 24 24\\" role=\\"img\\" aria-hidden=\\"true\\" focusable=\\"false\\"><path d=\\"M13 11.8l6.1-6.3-1-1-6.1 6.2-6.1-6.2-1 1 6.1 6.3-6.5 6.7 1 1 6.5-6.6 6.5 6.6 1-1z\\"></path></svg></button></div><div class=\\"components-panel\\"><div class=\\"components-panel__body sidebar-title-plugin-panel is-opened\\"><div class=\\"components-panel__row\\"><label for=\\"title-plain-text\\">Title:</label><textarea class=\\"block-editor-plain-text\\" id=\\"title-plain-text\\" placeholder=\\"(no title)\\" rows=\\"1\\" style=\\"overflow: hidden; overflow-wrap: break-word; resize: none; height: 18px;\\"></textarea></div><div class=\\"components-panel__row\\"><button type=\\"button\\" class=\\"components-button is-primary\\">Reset</button></div></div></div>"`; diff --git a/packages/e2e-tests/specs/editor/plugins/block-context.test.js b/packages/e2e-tests/specs/editor/plugins/block-context.test.js new file mode 100644 index 00000000000000..8f287bbb59add4 --- /dev/null +++ b/packages/e2e-tests/specs/editor/plugins/block-context.test.js @@ -0,0 +1,108 @@ +/** + * External dependencies + */ +import { last } from 'lodash'; + +/** + * WordPress dependencies + */ +import { + activatePlugin, + createNewPost, + deactivatePlugin, + insertBlock, + saveDraft, +} from '@wordpress/e2e-test-utils'; + +async function openPreviewPage( editorPage ) { + let openTabs = await browser.pages(); + const expectedTabsCount = openTabs.length + 1; + await editorPage.click( '.editor-post-preview__button-toggle' ); + await editorPage.waitFor( '.editor-post-preview__button-external' ); + await editorPage.click( '.editor-post-preview__button-external' ); + + // Wait for the new tab to open. + while ( openTabs.length < expectedTabsCount ) { + await editorPage.waitFor( 1 ); + openTabs = await browser.pages(); + } + + const previewPage = last( openTabs ); + // Wait for the preview to load. We can't do interstitial detection here, + // because it might load too quickly for us to pick up, so we wait for + // the preview to load by waiting for the content to appear. + await previewPage.waitForSelector( '.entry-content' ); + return previewPage; +} + +describe( 'Block context', () => { + beforeAll( async () => { + await activatePlugin( 'gutenberg-test-block-context' ); + } ); + + beforeEach( async () => { + await createNewPost(); + } ); + + afterAll( async () => { + await deactivatePlugin( 'gutenberg-test-block-context' ); + } ); + + test( 'Block context propagates to inner blocks', async () => { + await insertBlock( 'Test Context Provider' ); + + // Inserting the context provider block should select the first inner + // block of the template. Verify the contents of the consumer. + let innerBlockText = await page.evaluate( + () => document.activeElement.textContent + ); + expect( innerBlockText ).toBe( 'The record ID is: 0' ); + + // Change the attribute value associated with the context. + await page.keyboard.press( 'ArrowUp' ); + await page.keyboard.type( '123' ); + + // Verify propagated context changes. + await page.keyboard.press( 'ArrowDown' ); + innerBlockText = await page.evaluate( + () => document.activeElement.textContent + ); + expect( innerBlockText ).toBe( 'The record ID is: 123' ); + } ); + + test( 'Block context is reflected in the preview', async () => { + await insertBlock( 'Test Context Provider' ); + const editorPage = page; + const previewPage = await openPreviewPage( editorPage ); + + // Check default context values are populated. + let content = await previewPage.$eval( + '.entry-content', + ( contentWrapper ) => contentWrapper.textContent.trim() + ); + expect( content ).toBe( 'The record ID is: 0' ); + + // Return to editor to change context value to non-default. + await editorPage.bringToFront(); + await editorPage.focus( + '[data-type="gutenberg/test-context-provider"] input' + ); + await editorPage.keyboard.press( 'ArrowRight' ); + await editorPage.keyboard.type( '123' ); + await editorPage.waitForSelector( '.editor-post-save-draft' ); // Not entirely clear why it's asynchronous, but likely React scheduling prioritizing keyboard event and deferring the UI update. + await saveDraft(); + + // Check non-default context values are populated. + await previewPage.bringToFront(); + await previewPage.reload(); + content = await previewPage.$eval( + '.entry-content', + ( contentWrapper ) => contentWrapper.textContent.trim() + ); + expect( content ).toBe( 'The record ID is: 123' ); + + // Clean up + await editorPage.bringToFront(); + await previewPage.close(); + } ); +} ); diff --git a/packages/e2e-tests/specs/editor/plugins/block-icons.test.js b/packages/e2e-tests/specs/editor/plugins/block-icons.test.js index 2e5bcf666bb2bc..fd506d98fb3f7a 100644 --- a/packages/e2e-tests/specs/editor/plugins/block-icons.test.js +++ b/packages/e2e-tests/specs/editor/plugins/block-icons.test.js @@ -8,10 +8,11 @@ import { insertBlock, pressKeyWithModifier, searchForBlock, + openDocumentSettingsSidebar, } from '@wordpress/e2e-test-utils'; const INSERTER_BUTTON_SELECTOR = - '.components-popover__content .block-editor-block-types-list__item'; + '.block-editor-inserter__block-list .block-editor-block-types-list__item'; const INSERTER_ICON_WRAPPER_SELECTOR = `${ INSERTER_BUTTON_SELECTOR } .block-editor-block-types-list__item-icon`; const INSERTER_ICON_SELECTOR = `${ INSERTER_BUTTON_SELECTOR } .block-editor-block-icon`; const INSPECTOR_ICON_SELECTOR = '.edit-post-sidebar .block-editor-block-icon'; @@ -89,6 +90,7 @@ describe( 'Correctly Renders Block Icons on Inserter and Inspector', () => { it( 'Renders correctly the icon on the inspector', async () => { await insertBlock( blockTitle ); + await openDocumentSettingsSidebar(); await selectFirstBlock(); validateIcon( await getInnerHTML( INSPECTOR_ICON_SELECTOR ) ); } ); @@ -127,6 +129,7 @@ describe( 'Correctly Renders Block Icons on Inserter and Inspector', () => { it( 'Renders the icon in the inspector with the correct colors', async () => { await insertBlock( blockTitle ); + await openDocumentSettingsSidebar(); await selectFirstBlock(); validateDashIcon( await getInnerHTML( INSPECTOR_ICON_SELECTOR ) ); expect( @@ -153,6 +156,7 @@ describe( 'Correctly Renders Block Icons on Inserter and Inspector', () => { it( 'Renders correctly the icon on the inspector', async () => { await insertBlock( blockTitle ); + await openDocumentSettingsSidebar(); await selectFirstBlock(); validateSvgIcon( await getInnerHTML( INSPECTOR_ICON_SELECTOR ) ); expect( diff --git a/packages/e2e-tests/specs/editor/plugins/inner-blocks-allowed-blocks.test.js b/packages/e2e-tests/specs/editor/plugins/inner-blocks-allowed-blocks.test.js index 5d5318b97337c4..1e02d4369f1b3b 100644 --- a/packages/e2e-tests/specs/editor/plugins/inner-blocks-allowed-blocks.test.js +++ b/packages/e2e-tests/specs/editor/plugins/inner-blocks-allowed-blocks.test.js @@ -7,8 +7,8 @@ import { deactivatePlugin, getAllBlockInserterItemTitles, insertBlock, - openAllBlockInserterCategories, openGlobalBlockInserter, + closeGlobalBlockInserter, } from '@wordpress/e2e-test-utils'; describe( 'Allowed Blocks Setting on InnerBlocks ', () => { @@ -30,11 +30,11 @@ describe( 'Allowed Blocks Setting on InnerBlocks ', () => { const parentBlockSelector = '[data-type="test/allowed-blocks-unset"]'; const childParagraphSelector = `${ parentBlockSelector } ${ paragraphSelector }`; await insertBlock( 'Allowed Blocks Unset' ); + await closeGlobalBlockInserter(); await page.waitForSelector( childParagraphSelector ); await page.click( childParagraphSelector ); await openGlobalBlockInserter(); - await openAllBlockInserterCategories(); - expect( + await expect( ( await getAllBlockInserterItemTitles() ).length ).toBeGreaterThan( 20 ); } ); @@ -43,10 +43,10 @@ describe( 'Allowed Blocks Setting on InnerBlocks ', () => { const parentBlockSelector = '[data-type="test/allowed-blocks-set"]'; const childParagraphSelector = `${ parentBlockSelector } ${ paragraphSelector }`; await insertBlock( 'Allowed Blocks Set' ); + await closeGlobalBlockInserter(); await page.waitForSelector( childParagraphSelector ); await page.click( childParagraphSelector ); await openGlobalBlockInserter(); - await openAllBlockInserterCategories(); expect( await getAllBlockInserterItemTitles() ).toEqual( [ 'Button', 'Gallery', @@ -58,12 +58,12 @@ describe( 'Allowed Blocks Setting on InnerBlocks ', () => { it( 'correctly applies dynamic allowed blocks restrictions', async () => { await insertBlock( 'Allowed Blocks Dynamic' ); + await closeGlobalBlockInserter(); const parentBlockSelector = '[data-type="test/allowed-blocks-dynamic"]'; const blockAppender = '.block-list-appender button'; const appenderSelector = `${ parentBlockSelector } ${ blockAppender }`; await page.waitForSelector( appenderSelector ); await page.click( appenderSelector ); - await openAllBlockInserterCategories(); expect( await getAllBlockInserterItemTitles() ).toEqual( [ 'Image', 'List', @@ -73,8 +73,9 @@ describe( 'Allowed Blocks Setting on InnerBlocks ', () => { )[ 0 ]; await insertButton.click(); await insertBlock( 'Image' ); + await closeGlobalBlockInserter(); + await page.waitForSelector( '.product[data-number-of-children="2"]' ); await page.click( appenderSelector ); - await openAllBlockInserterCategories(); expect( await getAllBlockInserterItemTitles() ).toEqual( [ 'Gallery', 'Video', diff --git a/packages/e2e-tests/specs/editor/plugins/inner-blocks-render-appender.test.js b/packages/e2e-tests/specs/editor/plugins/inner-blocks-render-appender.test.js index ad27838a4a8ed1..137ac319a6800a 100644 --- a/packages/e2e-tests/specs/editor/plugins/inner-blocks-render-appender.test.js +++ b/packages/e2e-tests/specs/editor/plugins/inner-blocks-render-appender.test.js @@ -8,10 +8,10 @@ import { getAllBlockInserterItemTitles, getEditedPostContent, insertBlock, - openAllBlockInserterCategories, + closeGlobalBlockInserter, } from '@wordpress/e2e-test-utils'; -const INSERTER_RESULTS_SELECTOR = '.block-editor-inserter__results'; +const INSERTER_RESULTS_SELECTOR = '.block-editor-inserter__block-list'; const QUOTE_INSERT_BUTTON_SELECTOR = '//button[.="Quote"]'; const APPENDER_SELECTOR = '.my-custom-awesome-appender'; const DYNAMIC_APPENDER_SELECTOR = 'my-dynamic-blocks-appender'; @@ -32,6 +32,7 @@ describe( 'RenderAppender prop of InnerBlocks ', () => { it( 'Users can customize the appender and can still insert blocks using exposed components', async () => { // Insert the InnerBlocks renderAppender block. await insertBlock( 'InnerBlocks renderAppender' ); + await closeGlobalBlockInserter(); // Wait for the custom block appender to appear. await page.waitForSelector( APPENDER_SELECTOR ); // Verify if the custom block appender text is the expected one. @@ -46,8 +47,6 @@ describe( 'RenderAppender prop of InnerBlocks ', () => { await page.click( `${ APPENDER_SELECTOR } .block-editor-button-block-appender` ); - await openAllBlockInserterCategories(); - // Verify if the blocks the custom inserter is rendering are the expected ones. expect( await getAllBlockInserterItemTitles() ).toEqual( [ 'Quote', @@ -69,6 +68,7 @@ describe( 'RenderAppender prop of InnerBlocks ', () => { it( 'Users can dynamically customize the appender', async () => { // Insert the InnerBlocks renderAppender dynamic block. await insertBlock( 'InnerBlocks renderAppender dynamic' ); + await closeGlobalBlockInserter(); // Wait for the custom dynamic block appender to appear. await page.waitForSelector( '.' + DYNAMIC_APPENDER_SELECTOR ); @@ -81,7 +81,6 @@ describe( 'RenderAppender prop of InnerBlocks ', () => { // Open the inserter of our custom block appender and expand all the categories. const blockAppenderButtonSelector = `.${ DYNAMIC_APPENDER_SELECTOR } .block-editor-button-block-appender`; await page.click( blockAppenderButtonSelector ); - await openAllBlockInserterCategories(); // Verify if the blocks the custom inserter is rendering are the expected ones. expect( await getAllBlockInserterItemTitles() ).toEqual( [ diff --git a/packages/e2e-tests/specs/editor/plugins/plugins-api.test.js b/packages/e2e-tests/specs/editor/plugins/plugins-api.test.js index 627d3a7493f078..f4a385885e09f9 100644 --- a/packages/e2e-tests/specs/editor/plugins/plugins-api.test.js +++ b/packages/e2e-tests/specs/editor/plugins/plugins-api.test.js @@ -67,6 +67,9 @@ describe( 'Using Plugins API', () => { } ); describe( 'Sidebar', () => { + const SIDEBAR_PINNED_ITEM_BUTTON = + '.interface-pinned-items button[aria-label="Sidebar title plugin"]'; + const SIDEBAR_PANEL_SELECTOR = '.sidebar-title-plugin-panel'; it( 'Should open plugins sidebar using More Menu item and render content', async () => { await clickOnMoreMenuItem( 'Sidebar title plugin' ); @@ -77,6 +80,36 @@ describe( 'Using Plugins API', () => { expect( pluginSidebarContent ).toMatchSnapshot(); } ); + it( 'Should be pinned by default and can be opened and closed using pinned items', async () => { + const sidebarPinnedItem = await page.$( + SIDEBAR_PINNED_ITEM_BUTTON + ); + expect( sidebarPinnedItem ).not.toBeNull(); + await sidebarPinnedItem.click(); + expect( await page.$( SIDEBAR_PANEL_SELECTOR ) ).not.toBeNull(); + await sidebarPinnedItem.click(); + expect( await page.$( SIDEBAR_PANEL_SELECTOR ) ).toBeNull(); + } ); + + it( 'Can be pinned and unpinned', async () => { + await ( await page.$( SIDEBAR_PINNED_ITEM_BUTTON ) ).click(); + const unpinButton = await page.$( + 'button[aria-label="Unpin from toolbar"]' + ); + await unpinButton.click(); + expect( await page.$( SIDEBAR_PINNED_ITEM_BUTTON ) ).toBeNull(); + await page.click( + '.interface-complementary-area-header button[aria-label="Close plugin"]' + ); + await page.reload(); + expect( await page.$( SIDEBAR_PINNED_ITEM_BUTTON ) ).toBeNull(); + await clickOnMoreMenuItem( 'Sidebar title plugin' ); + await page.click( 'button[aria-label="Pin to toolbar"]' ); + expect( await page.$( SIDEBAR_PINNED_ITEM_BUTTON ) ).not.toBeNull(); + await page.reload(); + expect( await page.$( SIDEBAR_PINNED_ITEM_BUTTON ) ).not.toBeNull(); + } ); + it( 'Should close plugins sidebar using More Menu item', async () => { await clickOnMoreMenuItem( 'Sidebar title plugin' ); diff --git a/packages/e2e-tests/specs/editor/various/__snapshots__/block-hierarchy-navigation.test.js.snap b/packages/e2e-tests/specs/editor/various/__snapshots__/block-hierarchy-navigation.test.js.snap index 4ee1d7710bbe18..14f85661ea22e0 100644 --- a/packages/e2e-tests/specs/editor/various/__snapshots__/block-hierarchy-navigation.test.js.snap +++ b/packages/e2e-tests/specs/editor/various/__snapshots__/block-hierarchy-navigation.test.js.snap @@ -49,3 +49,15 @@ exports[`Navigating the block hierarchy should navigate using the block hierarch <!-- /wp:column --></div> <!-- /wp:columns -->" `; + +exports[`Navigating the block hierarchy should select the wrapper div for a group 1`] = ` +"<!-- wp:group --> +<div class=\\"wp-block-group\\"><div class=\\"wp-block-group__inner-container\\"><!-- wp:paragraph --> +<p>just a paragraph</p> +<!-- /wp:paragraph --> + +<!-- wp:separator --> +<hr class=\\"wp-block-separator\\"/> +<!-- /wp:separator --></div></div> +<!-- /wp:group -->" +`; diff --git a/packages/e2e-tests/specs/editor/various/__snapshots__/duplicating-blocks.test.js.snap b/packages/e2e-tests/specs/editor/various/__snapshots__/duplicating-blocks.test.js.snap new file mode 100644 index 00000000000000..bb8192de22cb94 --- /dev/null +++ b/packages/e2e-tests/specs/editor/various/__snapshots__/duplicating-blocks.test.js.snap @@ -0,0 +1,21 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Duplicating blocks should duplicate blocks using the block settings menu 1`] = ` +"<!-- wp:paragraph --> +<p>Clone me</p> +<!-- /wp:paragraph --> + +<!-- wp:paragraph --> +<p>Clone me</p> +<!-- /wp:paragraph -->" +`; + +exports[`Duplicating blocks should duplicate blocks using the keyboard shortcut 1`] = ` +"<!-- wp:paragraph --> +<p>Clone me</p> +<!-- /wp:paragraph --> + +<!-- wp:paragraph --> +<p>Clone me</p> +<!-- /wp:paragraph -->" +`; diff --git a/packages/e2e-tests/specs/editor/various/__snapshots__/font-size-picker.test.js.snap b/packages/e2e-tests/specs/editor/various/__snapshots__/font-size-picker.test.js.snap index 90f0c982aeca9e..bc58980c7ce536 100644 --- a/packages/e2e-tests/specs/editor/various/__snapshots__/font-size-picker.test.js.snap +++ b/packages/e2e-tests/specs/editor/various/__snapshots__/font-size-picker.test.js.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Font Size Picker should apply a custom font size using the font size input 1`] = ` -"<!-- wp:paragraph {\\"customFontSize\\":23} --> +"<!-- wp:paragraph {\\"style\\":{\\"typography\\":{\\"fontSize\\":23}}} --> <p style=\\"font-size:23px\\">Paragraph to be made \\"small\\"</p> <!-- /wp:paragraph -->" `; diff --git a/packages/e2e-tests/specs/editor/various/a11y.test.js b/packages/e2e-tests/specs/editor/various/a11y.test.js index 0ca44d7fb7114a..a25b5d9760c3ce 100644 --- a/packages/e2e-tests/specs/editor/various/a11y.test.js +++ b/packages/e2e-tests/specs/editor/various/a11y.test.js @@ -23,7 +23,7 @@ describe( 'a11y', () => { ':focus', ( focusedElement ) => { return focusedElement.classList.contains( - 'block-editor-inserter__toggle' + 'edit-post-header-toolbar__inserter-toggle' ); } ); diff --git a/packages/e2e-tests/specs/editor/various/adding-blocks.test.js b/packages/e2e-tests/specs/editor/various/adding-blocks.test.js index ed5244c50c189a..65fd287650b462 100644 --- a/packages/e2e-tests/specs/editor/various/adding-blocks.test.js +++ b/packages/e2e-tests/specs/editor/various/adding-blocks.test.js @@ -6,8 +6,8 @@ import { insertBlock, getEditedPostContent, pressKeyTimes, - switchEditorModeTo, setBrowserViewport, + closeGlobalBlockInserter, } from '@wordpress/e2e-test-utils'; /** @typedef {import('puppeteer').ElementHandle} ElementHandle */ @@ -42,7 +42,7 @@ describe( 'adding blocks', () => { // Click below editor to focus last field (block appender) await clickAtBottom( - await page.$( '.block-editor-editor-skeleton__content' ) + await page.$( '.interface-interface-skeleton__content' ) ); expect( await page.$( '[data-type="core/paragraph"]' ) ).not.toBeNull(); await page.keyboard.type( 'Paragraph block' ); @@ -92,6 +92,7 @@ describe( 'adding blocks', () => { // Unselect blocks to avoid conflicts with the inbetween inserter await page.click( '.editor-post-title__input' ); + await closeGlobalBlockInserter(); // Using the between inserter const insertionPoint = await page.$( '[data-type="core/quote"]' ); @@ -111,16 +112,14 @@ describe( 'adding blocks', () => { () => document.activeElement && document.activeElement.classList.contains( - 'block-editor-inserter__search' + 'block-editor-inserter__search-input' ) ); await page.keyboard.type( 'para' ); - await pressKeyTimes( 'Tab', 3 ); + await pressKeyTimes( 'Tab', 4 ); await page.keyboard.press( 'Enter' ); await page.keyboard.type( 'Second paragraph' ); - await switchEditorModeTo( 'Code' ); - expect( await getEditedPostContent() ).toMatchSnapshot(); } ); @@ -137,7 +136,7 @@ describe( 'adding blocks', () => { () => document.activeElement.classList ); expect( Object.values( activeElementClassList ) ).toContain( - 'block-editor-inserter__search' + 'block-editor-inserter__search-input' ); // Try using the up arrow key (vertical navigation triggers the issue described in #9583). @@ -148,29 +147,30 @@ describe( 'adding blocks', () => { () => document.activeElement.classList ); expect( Object.values( activeElementClassList ) ).toContain( - 'block-editor-inserter__search' + 'block-editor-inserter__search-input' ); - // Tab to the block search results + // Tab to the block list + await page.keyboard.press( 'Tab' ); await page.keyboard.press( 'Tab' ); - // Expect the search results to be the active element. + // Expect the block list to be the active element. activeElementClassList = await page.evaluate( () => document.activeElement.classList ); expect( Object.values( activeElementClassList ) ).toContain( - 'block-editor-inserter__results' + 'block-editor-block-types-list__item' ); // Try using the up arrow key await page.keyboard.press( 'ArrowUp' ); - // Expect the search results to still be the active element. + // Expect the block list to still be the active element. activeElementClassList = await page.evaluate( () => document.activeElement.classList ); expect( Object.values( activeElementClassList ) ).toContain( - 'block-editor-inserter__results' + 'block-editor-block-types-list__item' ); // Press escape to close the block inserter. diff --git a/packages/e2e-tests/specs/editor/various/adding-inline-tokens.test.js b/packages/e2e-tests/specs/editor/various/adding-inline-tokens.test.js index 0049bdd1d5c3f2..6c1017c6d53589 100644 --- a/packages/e2e-tests/specs/editor/various/adding-inline-tokens.test.js +++ b/packages/e2e-tests/specs/editor/various/adding-inline-tokens.test.js @@ -4,7 +4,7 @@ import path from 'path'; import fs from 'fs'; import os from 'os'; -import uuid from 'uuid/v4'; +import { v4 as uuid } from 'uuid'; /** * WordPress dependencies diff --git a/packages/e2e-tests/specs/editor/various/block-hierarchy-navigation.test.js b/packages/e2e-tests/specs/editor/various/block-hierarchy-navigation.test.js index 643998905e00e3..63ae6d57ecd1fb 100644 --- a/packages/e2e-tests/specs/editor/various/block-hierarchy-navigation.test.js +++ b/packages/e2e-tests/specs/editor/various/block-hierarchy-navigation.test.js @@ -7,6 +7,7 @@ import { getEditedPostContent, pressKeyTimes, pressKeyWithModifier, + openDocumentSettingsSidebar, } from '@wordpress/e2e-test-utils'; async function openBlockNavigator() { @@ -43,6 +44,7 @@ describe( 'Navigating the block hierarchy', () => { await columnsBlockMenuItem.click(); // Tweak the columns count. + await openDocumentSettingsSidebar(); await page.focus( '.block-editor-block-inspector .components-range-control__number[aria-label="Columns"]' ); @@ -73,6 +75,7 @@ describe( 'Navigating the block hierarchy', () => { it( 'should navigate block hierarchy using only the keyboard', async () => { await insertBlock( 'Columns' ); + await openDocumentSettingsSidebar(); await page.click( '[aria-label="Two columns; equal split"]' ); // Add a paragraph in the first column. @@ -91,7 +94,7 @@ describe( 'Navigating the block hierarchy', () => { await pressKeyWithModifier( 'ctrl', '`' ); await pressKeyWithModifier( 'ctrl', '`' ); await pressKeyWithModifier( 'ctrl', '`' ); - await pressKeyTimes( 'Tab', 4 ); + await pressKeyTimes( 'Tab', 5 ); // Tweak the columns count by increasing it by one. await page.keyboard.press( 'ArrowRight' ); @@ -135,4 +138,42 @@ describe( 'Navigating the block hierarchy', () => { expect( await getEditedPostContent() ).toMatchSnapshot(); } ); + + it( 'should select the wrapper div for a group ', async () => { + // Insert a group block + await insertBlock( 'Group' ); + + // Insert some random blocks. + // The last block shouldn't be a textual block. + await page.click( '.block-list-appender .block-editor-inserter' ); + const paragraphMenuItem = ( + await page.$x( `//button//span[contains(text(), 'Paragraph')]` ) + )[ 0 ]; + await paragraphMenuItem.click(); + await page.keyboard.type( 'just a paragraph' ); + await insertBlock( 'Separator' ); + + // Check the Group block content + expect( await getEditedPostContent() ).toMatchSnapshot(); + + // Unselect the blocks + await page.click( '.editor-post-title' ); + + // Try selecting the group block using the block navigation + await page.click( '[aria-label="Block navigation"]' ); + const groupMenuItem = ( + await page.$x( + "//button[contains(@class,'block-editor-block-navigation__item') and contains(text(), 'Group')]" + ) + )[ 0 ]; + await groupMenuItem.click(); + + // The group block's wrapper should be selected. + const isGroupBlockSelected = await page.evaluate( + () => + document.activeElement.getAttribute( 'data-type' ) === + 'core/group' + ); + expect( isGroupBlockSelected ).toBe( true ); + } ); } ); diff --git a/packages/e2e-tests/specs/editor/various/block-switcher.test.js b/packages/e2e-tests/specs/editor/various/block-switcher.test.js index 12c40442195160..c330f8680af551 100644 --- a/packages/e2e-tests/specs/editor/various/block-switcher.test.js +++ b/packages/e2e-tests/specs/editor/various/block-switcher.test.js @@ -9,7 +9,7 @@ import { pressKeyWithModifier, } from '@wordpress/e2e-test-utils'; -describe( 'adding blocks', () => { +describe( 'Block Switcher', () => { beforeEach( async () => { await createNewPost(); } ); diff --git a/packages/e2e-tests/specs/editor/various/convert-block-type.test.js b/packages/e2e-tests/specs/editor/various/convert-block-type.test.js index 2c71a3d3a139f2..101a40b6dd2299 100644 --- a/packages/e2e-tests/specs/editor/various/convert-block-type.test.js +++ b/packages/e2e-tests/specs/editor/various/convert-block-type.test.js @@ -17,8 +17,7 @@ describe( 'Code block', () => { const code = 'print "Hello Dolly!"'; await insertBlock( 'Code' ); - - await page.type( '.block-editor-block-list__block textarea', code ); + await page.keyboard.type( code ); // Verify the content starts out as a Code block. const originalPostContent = await getEditedPostContent(); diff --git a/packages/e2e-tests/specs/editor/various/duplicating-blocks.test.js b/packages/e2e-tests/specs/editor/various/duplicating-blocks.test.js new file mode 100644 index 00000000000000..a5aadb7766a793 --- /dev/null +++ b/packages/e2e-tests/specs/editor/various/duplicating-blocks.test.js @@ -0,0 +1,49 @@ +/** + * WordPress dependencies + */ +import { + createNewPost, + insertBlock, + getEditedPostContent, + clickBlockToolbarButton, + pressKeyWithModifier, +} from '@wordpress/e2e-test-utils'; + +describe( 'Duplicating blocks', () => { + beforeEach( async () => { + await createNewPost(); + } ); + + it( 'should duplicate blocks using the block settings menu', async () => { + await insertBlock( 'Paragraph' ); + await page.keyboard.type( 'Clone me' ); + + // Select the test we just typed + // This doesn't do anything but we previously had a duplicationi bug + // When the selection was not collapsed + await pressKeyWithModifier( 'primary', 'a' ); + + await clickBlockToolbarButton( 'More options' ); + const duplicateButton = await page.waitForXPath( + '//button[text()="Duplicate"]' + ); + await duplicateButton.click(); + + expect( await getEditedPostContent() ).toMatchSnapshot(); + } ); + + it( 'should duplicate blocks using the keyboard shortcut', async () => { + await insertBlock( 'Paragraph' ); + await page.keyboard.type( 'Clone me' ); + + // Select the test we just typed + // This doesn't do anything but we previously had a duplicationi bug + // When the selection was not collapsed + await pressKeyWithModifier( 'primary', 'a' ); + + // Duplicate using the keyboard shortccut + await pressKeyWithModifier( 'primaryShift', 'd' ); + + expect( await getEditedPostContent() ).toMatchSnapshot(); + } ); +} ); diff --git a/packages/e2e-tests/specs/editor/various/editor-modes.test.js b/packages/e2e-tests/specs/editor/various/editor-modes.test.js index 15d767cd6cc2c9..6aef17cd69594d 100644 --- a/packages/e2e-tests/specs/editor/various/editor-modes.test.js +++ b/packages/e2e-tests/specs/editor/various/editor-modes.test.js @@ -146,7 +146,7 @@ describe( 'Editing modes (visual/HTML)', () => { // The inserter is disabled const disabledInserter = await page.$( - '.block-editor-inserter > button:disabled, .block-editor-inserter > button[aria-disabled="true"]' + '.edit-post-header-toolbar__inserter-toggle:disabled, .edit-post-header-toolbar__inserter-toggle[aria-disabled="true"]' ); expect( disabledInserter ).not.toBeNull(); } ); diff --git a/packages/e2e-tests/specs/editor/various/embedding.test.js b/packages/e2e-tests/specs/editor/various/embedding.test.js index b33a24fd787208..9e30ec116f3c37 100644 --- a/packages/e2e-tests/specs/editor/various/embedding.test.js +++ b/packages/e2e-tests/specs/editor/various/embedding.test.js @@ -307,7 +307,7 @@ describe( 'Embedding content', () => { await page.keyboard.type( 'Hello there!' ); await publishPost(); const postUrl = await page.$eval( - '[id^=inspector-text-control-]', + '.editor-post-publish-panel [id^=inspector-text-control-]', ( el ) => el.value ); diff --git a/packages/e2e-tests/specs/editor/various/is-typing.test.js b/packages/e2e-tests/specs/editor/various/is-typing.test.js new file mode 100644 index 00000000000000..8161118d65944d --- /dev/null +++ b/packages/e2e-tests/specs/editor/various/is-typing.test.js @@ -0,0 +1,99 @@ +/** + * WordPress dependencies + */ +import { clickBlockAppender, createNewPost } from '@wordpress/e2e-test-utils'; + +describe( 'isTyping', () => { + beforeEach( async () => { + await createNewPost(); + } ); + + it( 'should hide the toolbar when typing', async () => { + const blockToolbarSelector = '.block-editor-block-toolbar'; + + await clickBlockAppender(); + + // Type in a paragraph + await page.keyboard.type( 'Type' ); + + // Toolbar is hidden + let blockToolbar = await page.$( blockToolbarSelector ); + expect( blockToolbar ).toBe( null ); + + // Moving the mouse shows the toolbar + await page.mouse.move( 0, 0 ); + await page.mouse.move( 10, 10 ); + + // Toolbar is visible + blockToolbar = await page.$( blockToolbarSelector ); + expect( blockToolbar ).not.toBe( null ); + + // Typing again hides the toolbar + await page.keyboard.type( ' and continue' ); + + // Toolbar is hidden again + blockToolbar = await page.$( blockToolbarSelector ); + expect( blockToolbar ).toBe( null ); + } ); + + it( 'should not close the dropdown when typing in it', async () => { + // Adds a Dropdown with an input to all blocks + await page.evaluate( () => { + const { Dropdown, Button, Fill } = wp.components; + const { createElement: el, Fragment } = wp.element; + function AddDropdown( BlockListBlock ) { + return ( props ) => { + return el( + Fragment, + {}, + el( + Fill, + { name: 'BlockControls' }, + el( Dropdown, { + renderToggle: ( { onToggle } ) => + el( + Button, + { + onClick: onToggle, + className: 'dropdown-open', + }, + 'Open Dropdown' + ), + renderContent: () => + el( 'input', { + className: 'dropdown-input', + } ), + } ) + ), + el( BlockListBlock, props ) + ); + }; + } + + wp.hooks.addFilter( + 'editor.BlockListBlock', + 'e2e-test/add-dropdown', + AddDropdown + ); + } ); + + await clickBlockAppender(); + + // Type in a paragraph + await page.keyboard.type( 'Type' ); + + // Show Toolbar + await page.mouse.move( 0, 0 ); + await page.mouse.move( 10, 10 ); + + // Open the dropdown + await page.click( '.dropdown-open' ); + + // Type inside the dropdown's input + await page.type( '.dropdown-input', 'Random' ); + + // The input should still be visible + const input = await page.$( '.dropdown-input' ); + expect( input ).not.toBe( null ); + } ); +} ); diff --git a/packages/e2e-tests/specs/editor/various/keyboard-navigable-blocks.test.js b/packages/e2e-tests/specs/editor/various/keyboard-navigable-blocks.test.js index 7226e0750e5726..8f7d6818d380d3 100644 --- a/packages/e2e-tests/specs/editor/various/keyboard-navigable-blocks.test.js +++ b/packages/e2e-tests/specs/editor/various/keyboard-navigable-blocks.test.js @@ -22,6 +22,7 @@ const navigateToContentEditorTop = async () => { // Use 'Ctrl+`' to return to the top of the editor await pressKeyWithModifier( 'ctrl', '`' ); await pressKeyWithModifier( 'ctrl', '`' ); + await pressKeyWithModifier( 'ctrl', '`' ); }; const tabThroughParagraphBlock = async ( paragraphText ) => { @@ -38,7 +39,7 @@ const tabThroughParagraphBlock = async ( paragraphText ) => { ).toBe( paragraphText ); await page.keyboard.press( 'Tab' ); - await expect( await getActiveLabel() ).toBe( 'Document' ); + await expect( await getActiveLabel() ).toBe( 'Open document settings' ); }; const tabThroughBlockMoverControl = async () => { @@ -133,7 +134,7 @@ describe( 'Order of block keyboard navigation', () => { ); await page.keyboard.press( 'Tab' ); - await expect( await getActiveLabel() ).toBe( 'Document (selected)' ); + await expect( await getActiveLabel() ).toBe( 'Open document settings' ); } ); it( 'allows tabbing in navigation mode if no block is selected (reverse)', async () => { @@ -149,7 +150,7 @@ describe( 'Order of block keyboard navigation', () => { await page.evaluate( () => { document.querySelector( '.edit-post-visual-editor' ).focus(); document - .querySelector( '.block-editor-editor-skeleton__sidebar' ) + .querySelector( '.interface-interface-skeleton__sidebar' ) .focus(); } ); diff --git a/packages/e2e-tests/specs/editor/various/links.test.js b/packages/e2e-tests/specs/editor/various/links.test.js index c16bca2cd38422..584276c1807f88 100644 --- a/packages/e2e-tests/specs/editor/various/links.test.js +++ b/packages/e2e-tests/specs/editor/various/links.test.js @@ -9,12 +9,6 @@ import { pressKeyWithModifier, } from '@wordpress/e2e-test-utils'; -/** - * The modifier keys needed to invoke a 'select the next word' keyboard shortcut. - * - * @type {string} - */ - describe( 'Links', () => { beforeEach( async () => { await createNewPost(); @@ -26,6 +20,42 @@ describe( 'Links', () => { ); }; + it( 'will use Post title as link text if link to existing post is created without any text selected', async () => { + const titleText = 'Post to create a link to'; + await createPostWithTitle( titleText ); + + await createNewPost(); + await clickBlockAppender(); + + // Now in a new post and try to create a link from an autocomplete suggestion using the keyboard. + await page.keyboard.type( 'Here comes a link: ' ); + + // Press Cmd+K to insert a link + await pressKeyWithModifier( 'primary', 'K' ); + + // Wait for the URL field to auto-focus + await waitForAutoFocus(); + expect( + await page.$( + '.components-popover__content .block-editor-link-control' + ) + ).not.toBeNull(); + + // Trigger the autocomplete suggestion list and select the first suggestion. + await page.keyboard.type( titleText.substr( 0, titleText.length - 2 ) ); + await page.waitForSelector( '.block-editor-link-control__search-item' ); + await page.keyboard.press( 'ArrowDown' ); + + await page.keyboard.press( 'Enter' ); + + const actualText = await page.evaluate( + () => + document.querySelector( '.block-editor-rich-text__editable a' ) + .textContent + ); + expect( actualText ).toBe( titleText ); + } ); + it( 'can be created by selecting text and clicking Link', async () => { // Create a block with some text await clickBlockAppender(); @@ -122,6 +152,9 @@ describe( 'Links', () => { await pressKeyWithModifier( 'shiftAlt', 'ArrowLeft' ); await pressKeyWithModifier( 'shiftAlt', 'ArrowLeft' ); await pressKeyWithModifier( 'shiftAlt', 'ArrowLeft' ); + await pressKeyWithModifier( 'shiftAlt', 'ArrowLeft' ); + await pressKeyWithModifier( 'shiftAlt', 'ArrowLeft' ); + await pressKeyWithModifier( 'shiftAlt', 'ArrowLeft' ); // Click on the Link button await page.click( 'button[aria-label="Link"]' ); @@ -170,6 +203,9 @@ describe( 'Links', () => { // Click on the Submit button await page.keyboard.press( 'Enter' ); + + // Reselect the link. + await pressKeyWithModifier( 'shiftAlt', 'ArrowLeft' ); }; it( 'can be edited', async () => { @@ -466,13 +502,6 @@ describe( 'Links', () => { await waitForAutoFocus(); await page.keyboard.type( 'w.org' ); - // Insert the link - await page.keyboard.press( 'Enter' ); - - // Navigate back to the popover - await pressKeyWithModifier( 'primary', 'k' ); - await waitForAutoFocus(); - // Navigate to and toggle the "Open in new tab" checkbox. await page.keyboard.press( 'Tab' ); await page.keyboard.press( 'Tab' ); @@ -484,7 +513,8 @@ describe( 'Links', () => { // Close dialog. Expect that "Open in new tab" would have been applied // immediately. - await page.keyboard.press( 'Escape' ); + await page.keyboard.press( 'Tab' ); + await page.keyboard.press( 'Enter' ); expect( await getEditedPostContent() ).toMatchSnapshot(); @@ -495,9 +525,10 @@ describe( 'Links', () => { // // See: https://github.com/WordPress/gutenberg/pull/15573 - // Collapse selection. + // Move caret back into the link. await page.keyboard.press( 'ArrowLeft' ); - await page.keyboard.press( 'ArrowRight' ); + await page.keyboard.press( 'ArrowLeft' ); + // Edit link. await pressKeyWithModifier( 'primary', 'k' ); await page.waitForSelector( @@ -513,6 +544,10 @@ describe( 'Links', () => { await page.keyboard.press( 'Enter' ); // Navigate back to the popover + await page.keyboard.press( 'ArrowLeft' ); + await page.keyboard.press( 'ArrowLeft' ); + + // Navigate back to inputs to verify appears as changed. await pressKeyWithModifier( 'primary', 'k' ); await waitForAutoFocus(); diff --git a/packages/e2e-tests/specs/editor/various/reusable-blocks.test.js b/packages/e2e-tests/specs/editor/various/reusable-blocks.test.js index 291e5852ce34e4..f57b1f96c3a73e 100644 --- a/packages/e2e-tests/specs/editor/various/reusable-blocks.test.js +++ b/packages/e2e-tests/specs/editor/various/reusable-blocks.test.js @@ -164,6 +164,56 @@ describe( 'Reusable blocks', () => { expect( text ).toMatch( 'Oh! Hello there!' ); } ); + it( 'can be inserted after refresh', async () => { + // Step 1. Insert a paragraph block + + await insertBlock( 'Paragraph' ); + await page.keyboard.type( 'Awesome Paragraph' ); + + await clickBlockToolbarButton( 'More options' ); + + const convertButton = await page.waitForXPath( + '//button[text()="Add to Reusable blocks"]' + ); + await convertButton.click(); + + // Wait for creation to finish + await page.waitForXPath( + '//*[contains(@class, "components-snackbar")]/*[text()="Block created."]' + ); + + // Select all of the text in the title field. + await pressKeyWithModifier( 'primary', 'a' ); + + // Give the reusable block a title + await page.keyboard.type( 'Awesome block' ); + + // Save the reusable block + const [ saveButton ] = await page.$x( '//button[text()="Save"]' ); + await saveButton.click(); + + // Step 2. Create new post. + + await createNewPost(); + + // Step 3. Insert the block created in Step 1. + + await insertBlock( 'Awesome block' ); + + // Check that we have a reusable block on the page + const block = await page.$( + '.block-editor-block-list__block[data-type="core/block"]' + ); + expect( block ).not.toBeNull(); + + // Check that its title is displayed + const title = await page.$eval( + '.reusable-block-edit-panel__info', + ( element ) => element.innerText + ); + expect( title ).toBe( 'Awesome block' ); + } ); + it( 'can be converted to a regular block', async () => { // Insert the reusable block we edited above await insertBlock( 'Surprised greeting block' ); diff --git a/packages/e2e-tests/specs/editor/various/rich-text.test.js b/packages/e2e-tests/specs/editor/various/rich-text.test.js index cd3fa85e62fdcf..e29475984b7f88 100644 --- a/packages/e2e-tests/specs/editor/various/rich-text.test.js +++ b/packages/e2e-tests/specs/editor/various/rich-text.test.js @@ -7,6 +7,7 @@ import { insertBlock, clickBlockAppender, pressKeyWithModifier, + openDocumentSettingsSidebar, } from '@wordpress/e2e-test-utils'; describe( 'RichText', () => { @@ -22,6 +23,7 @@ describe( 'RichText', () => { // // See: https://github.com/WordPress/gutenberg/issues/3091 await insertBlock( 'Heading' ); + await openDocumentSettingsSidebar(); await page.click( '[aria-label="Heading 3"]' ); expect( await getEditedPostContent() ).toMatchSnapshot(); diff --git a/packages/e2e-tests/specs/editor/various/sidebar.test.js b/packages/e2e-tests/specs/editor/various/sidebar.test.js index ab2043f17b887a..a9d4dfdd2135e2 100644 --- a/packages/e2e-tests/specs/editor/various/sidebar.test.js +++ b/packages/e2e-tests/specs/editor/various/sidebar.test.js @@ -87,8 +87,7 @@ describe( 'Sidebar', () => { await setBrowserViewport( 'large' ); - const sidebarsDesktop = await page.$$( SIDEBAR_SELECTOR ); - expect( sidebarsDesktop ).toHaveLength( 1 ); + await page.waitForSelector( SIDEBAR_SELECTOR ); } ); it( 'should preserve tab order while changing active tab', async () => { diff --git a/packages/e2e-tests/specs/editor/various/writing-flow.test.js b/packages/e2e-tests/specs/editor/various/writing-flow.test.js index d06176cc7de460..7a379731f8789a 100644 --- a/packages/e2e-tests/specs/editor/various/writing-flow.test.js +++ b/packages/e2e-tests/specs/editor/various/writing-flow.test.js @@ -39,7 +39,9 @@ describe( 'Writing Flow', () => { await page.keyboard.press( 'Enter' ); await page.click( ':focus [aria-label="Two columns; equal split"]' ); await page.click( ':focus .block-editor-button-block-appender' ); - await page.waitForSelector( ':focus.block-editor-inserter__search' ); + await page.waitForSelector( + ':focus.block-editor-inserter__search-input' + ); await page.keyboard.type( 'Paragraph' ); await pressKeyTimes( 'Tab', 3 ); // Tab to paragraph result. await page.keyboard.press( 'Enter' ); // Insert paragraph. @@ -50,7 +52,9 @@ describe( 'Writing Flow', () => { // is a temporary solution. await page.focus( '.wp-block[data-type="core/column"]:nth-child(2)' ); await page.click( ':focus .block-editor-button-block-appender' ); - await page.waitForSelector( ':focus.block-editor-inserter__search' ); + await page.waitForSelector( + ':focus.block-editor-inserter__search-input' + ); await page.keyboard.type( 'Paragraph' ); await pressKeyTimes( 'Tab', 3 ); // Tab to paragraph result. await page.keyboard.press( 'Enter' ); // Insert paragraph. diff --git a/packages/e2e-tests/specs/experiments/__snapshots__/navigation.test.js.snap b/packages/e2e-tests/specs/experiments/__snapshots__/navigation.test.js.snap index 9bef34b8e46192..e41ca54dee0304 100644 --- a/packages/e2e-tests/specs/experiments/__snapshots__/navigation.test.js.snap +++ b/packages/e2e-tests/specs/experiments/__snapshots__/navigation.test.js.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Navigation allows a navigation menu to be created from an empty menu using a mixture of internal and external links 1`] = ` -"<!-- wp:navigation --> +"<!-- wp:navigation {\\"orientation\\":\\"horizontal\\"} --> <!-- wp:navigation-link {\\"label\\":\\"WP\\",\\"id\\":\\"https://wordpress.org\\",\\"url\\":\\"https://wordpress.org\\"} /--> <!-- wp:navigation-link {\\"label\\":\\"Contact\\",\\"id\\":1,\\"url\\":\\"https://this/is/a/test/search/get-in-touch\\"} /--> @@ -9,7 +9,7 @@ exports[`Navigation allows a navigation menu to be created from an empty menu us `; exports[`Navigation allows a navigation menu to be created using existing pages 1`] = ` -"<!-- wp:navigation --> +"<!-- wp:navigation {\\"orientation\\":\\"horizontal\\"} --> <!-- wp:navigation-link {\\"label\\":\\"Home\\",\\"type\\":\\"page\\",\\"id\\":1,\\"url\\":\\"https://this/is/a/test/page/home\\"} /--> <!-- wp:navigation-link {\\"label\\":\\"About\\",\\"type\\":\\"page\\",\\"id\\":2,\\"url\\":\\"https://this/is/a/test/page/about\\"} /--> @@ -19,7 +19,7 @@ exports[`Navigation allows a navigation menu to be created using existing pages `; exports[`Navigation allows pages to be created from the navigation block and their links added to menu 1`] = ` -"<!-- wp:navigation --> +"<!-- wp:navigation {\\"orientation\\":\\"horizontal\\"} --> <!-- wp:navigation-link {\\"label\\":\\"A really long page name that will not exist\\",\\"id\\":1,\\"url\\":\\"https://this/is/a/test/create/page/my-new-page\\"} /--> <!-- /wp:navigation -->" `; diff --git a/packages/e2e-tests/specs/experiments/multi-entity-saving.test.js b/packages/e2e-tests/specs/experiments/multi-entity-saving.test.js new file mode 100644 index 00000000000000..20f7611b05341e --- /dev/null +++ b/packages/e2e-tests/specs/experiments/multi-entity-saving.test.js @@ -0,0 +1,193 @@ +/** + * WordPress dependencies + */ +import { + createNewPost, + insertBlock, + disablePrePublishChecks, + publishPostWithPrePublishChecksDisabled, + visitAdminPage, +} from '@wordpress/e2e-test-utils'; +import { addQueryArgs } from '@wordpress/url'; + +/** + * Internal dependencies + */ +import { + enableExperimentalFeatures, + disableExperimentalFeatures, +} from '../../experimental-features'; +import { trashExistingPosts } from '../../config/setup-test-framework'; + +describe( 'Multi-entity save flow', () => { + // Selectors. + const checkedBoxSelector = '.components-checkbox-control__checked'; + const checkboxInputSelector = '.components-checkbox-control__input'; + const demoTemplateSelector = '//button[contains(., "front-page")]'; + const draftSavedSelector = '.editor-post-saved-state.is-saved'; + const entitiesSaveSelector = '.editor-entities-saved-states__save-button'; + const multiSaveSelector = + '.editor-post-publish-button__button.has-changes-dot'; + const savePostSelector = '.editor-post-publish-button__button'; + const disabledSavePostSelector = `${ savePostSelector }[aria-disabled=true]`; + const enabledSavePostSelector = `${ savePostSelector }[aria-disabled=false]`; + const saveSiteSelector = '.edit-site-save-button__button'; + const activeSaveSiteSelector = `${ saveSiteSelector }[aria-disabled=false]`; + const disabledSaveSiteSelector = `${ saveSiteSelector }[aria-disabled=true]`; + const templateDropdownSelector = + '.components-dropdown-menu__toggle[aria-label="Switch Template"]'; + const templatePartSelector = '*[data-type="core/template-part"]'; + const activatedTemplatePartSelector = `${ templatePartSelector } .block-editor-inner-blocks`; + + // Reusable assertions across Post/Site editors. + const assertAllBoxesChecked = async () => { + const checkedBoxes = await page.$$( checkedBoxSelector ); + const checkboxInputs = await page.$$( checkboxInputSelector ); + expect( checkedBoxes.length - checkboxInputs.length ).toBe( 0 ); + }; + // Setup & Teardown. + const requiredExperiments = [ + '#gutenberg-full-site-editing', + '#gutenberg-full-site-editing-demo', + ]; + beforeAll( async () => { + await enableExperimentalFeatures( requiredExperiments ); + await trashExistingPosts( 'wp_template' ); + await trashExistingPosts( 'wp_template_part' ); + } ); + afterAll( async () => { + await disableExperimentalFeatures( requiredExperiments ); + } ); + + describe( 'Post Editor', () => { + // Reusable assertions inside Post editor. + const assertMultiSaveEnabled = async () => { + const multiSaveButton = await page.waitForSelector( + multiSaveSelector + ); + expect( multiSaveButton ).not.toBeNull(); + }; + const assertMultiSaveDisabled = async () => { + const multiSaveButton = await page.$( multiSaveSelector ); + expect( multiSaveButton ).toBeNull(); + }; + + describe( 'Pre-Publish state', () => { + it( 'Should not trigger multi-entity save button with only post edited', async () => { + await createNewPost(); + await disablePrePublishChecks(); + // Edit the page some. + await page.click( '.editor-post-title' ); + await page.keyboard.type( 'Test Post...' ); + await page.keyboard.press( 'Enter' ); + + await assertMultiSaveDisabled(); + } ); + + it( 'Should trigger multi-entity save button once template part edited', async () => { + // Create new template part. + await insertBlock( 'Template Part' ); + await page.keyboard.type( 'test-template-part' ); + await page.keyboard.press( 'Tab' ); + await page.keyboard.type( 'test-theme' ); + await page.keyboard.press( 'Tab' ); + await page.keyboard.press( 'Enter' ); + + // Make some changes in new Template Part. + await page.waitForSelector( activatedTemplatePartSelector ); + await page.click( templatePartSelector ); + await page.keyboard.type( 'some words...' ); + + await assertMultiSaveEnabled(); + } ); + + it( 'Clicking should open modal with boxes checked by default', async () => { + await page.click( savePostSelector ); + await assertAllBoxesChecked(); + } ); + + it( 'Saving should result in items being saved', async () => { + await page.click( entitiesSaveSelector ); + + // Verify post is saved. + const draftSaved = await page.waitForSelector( + draftSavedSelector + ); + expect( draftSaved ).not.toBeNull(); + + // Verify template part is saved. + await assertMultiSaveDisabled(); + } ); + } ); + + describe( 'Published state', () => { + it( 'Update button disabled after publish', async () => { + await publishPostWithPrePublishChecksDisabled(); + const disabledSaveButton = await page.$( + disabledSavePostSelector + ); + expect( disabledSaveButton ).not.toBeNull(); + } ); + + it( 'Update button enabled after editing post', async () => { + await page.click( '.editor-post-title' ); + await page.keyboard.type( '...more title!' ); + + // Verify update button is enabled. + const enabledSaveButton = await page.$( + enabledSavePostSelector + ); + expect( enabledSaveButton ).not.toBeNull(); + + // Verify is not for multi-entity saving. + await assertMultiSaveDisabled(); + } ); + + it( 'Multi-save button triggered after editing template part.', async () => { + await page.click( templatePartSelector ); + await page.keyboard.type( '...some more words...' ); + await page.keyboard.press( 'Enter' ); + await assertMultiSaveEnabled(); + } ); + } ); + } ); + + describe( 'Site Editor', () => { + it( 'Should be enabled after edits', async () => { + // Navigate to site editor. + const query = addQueryArgs( '', { + page: 'gutenberg-edit-site', + } ).slice( 1 ); + await visitAdminPage( 'admin.php', query ); + + // Ensure we are on 'front-page' demo template. + await page.click( templateDropdownSelector ); + const [ demoTemplateButton ] = await page.$x( + demoTemplateSelector + ); + await demoTemplateButton.click(); + + // Insert a new template part placeholder. + await insertBlock( 'Template Part' ); + + const enabledButton = await page.waitForSelector( + activeSaveSiteSelector + ); + + expect( enabledButton ).not.toBeNull(); + } ); + + it( 'Clicking button should open modal with boxes checked', async () => { + await page.click( activeSaveSiteSelector ); + await assertAllBoxesChecked(); + } ); + + it( 'Saving should result in items being saved', async () => { + await page.click( entitiesSaveSelector ); + const disabledButton = await page.waitForSelector( + disabledSaveSiteSelector + ); + expect( disabledButton ).not.toBeNull(); + } ); + } ); +} ); diff --git a/packages/e2e-tests/specs/experiments/navigation.test.js b/packages/e2e-tests/specs/experiments/navigation.test.js index fc11a057968fa2..948158e30dbd4c 100644 --- a/packages/e2e-tests/specs/experiments/navigation.test.js +++ b/packages/e2e-tests/specs/experiments/navigation.test.js @@ -77,9 +77,10 @@ async function mockCreatePageResponse( title, slug ) { /** * Interacts with the LinkControl to perform a search and select a returned suggestion * - * @param {string} url What will be typed in the search input - * @param {string} label What the resulting label will be in the creating Navigation Link Block after the block is created. - * @param {string} type What kind of suggestion should be clicked, ie. 'url', 'create', or 'entity' + * @param {Object} link link object to be tested + * @param {string} link.url What will be typed in the search input + * @param {string} link.label What the resulting label will be in the creating Navigation Link Block after the block is created. + * @param {string} link.type What kind of suggestion should be clicked, ie. 'url', 'create', or 'entity' */ async function updateActiveNavigationLink( { url, label, type } ) { const typeClasses = { @@ -311,6 +312,7 @@ describe( 'Navigation', () => { document.activeElement.innerText === 'A really long page name that will not exist' ); + expect( isInLinkRichText ).toBe( true ); // Expect a Navigation Block with a link for "A really long page name that will not exist". diff --git a/packages/e2e-tests/specs/performance/performance.test.js b/packages/e2e-tests/specs/performance/performance.test.js index b4ba1419bb9475..9360c98a6d313e 100644 --- a/packages/e2e-tests/specs/performance/performance.test.js +++ b/packages/e2e-tests/specs/performance/performance.test.js @@ -47,13 +47,17 @@ function isKeyUpEvent( item ) { return isKeyEvent( item ) && item.args.data.type === 'keyup'; } +function isFocusEvent( item ) { + return isKeyEvent( item ) && item.args.data.type === 'focus'; +} + function getEventDurationsForType( trace, filterFunction ) { return trace.traceEvents .filter( filterFunction ) .map( ( item ) => item.dur / 1000 ); } -function getEventDurations( trace ) { +function getTypingEventDurations( trace ) { return [ getEventDurationsForType( trace, isKeyDownEvent ), getEventDurationsForType( trace, isKeyPressEvent ), @@ -61,8 +65,21 @@ function getEventDurations( trace ) { ]; } +function getSelectionEventDurations( trace ) { + return [ getEventDurationsForType( trace, isFocusEvent ) ]; +} + +jest.setTimeout( 1000000 ); + describe( 'Performance', () => { - it( '1000 paragraphs', async () => { + it( 'Loading, typing and selecting blocks', async () => { + const results = { + load: [], + domcontentloaded: [], + type: [], + focus: [], + }; + const html = readFile( join( __dirname, '../../assets/large-post.html' ) ); @@ -84,14 +101,9 @@ describe( 'Performance', () => { }, html ); await saveDraft(); - const results = { - load: [], - domcontentloaded: [], - type: [], - }; - let i = 1; + // Measuring loading time while ( i-- ) { await page.reload( { waitUntil: [ 'domcontentloaded', 'load' ] } ); const timings = JSON.parse( @@ -110,29 +122,26 @@ describe( 'Performance', () => { ); } + // Measuring typing performance await insertBlock( 'Paragraph' ); - i = 200; const traceFile = __dirname + '/trace.json'; - await page.tracing.start( { path: traceFile, screenshots: false, categories: [ 'devtools.timeline' ], } ); - while ( i-- ) { await page.keyboard.type( 'x' ); } await page.tracing.stop(); - - const traceResults = JSON.parse( readFile( traceFile ) ); + let traceResults = JSON.parse( readFile( traceFile ) ); const [ keyDownEvents, keyPressEvents, keyUpEvents, - ] = getEventDurations( traceResults ); + ] = getTypingEventDurations( traceResults ); if ( keyDownEvents.length === keyPressEvents.length && @@ -145,6 +154,34 @@ describe( 'Performance', () => { } } + // Measuring block selection performance + await createNewPost(); + await page.evaluate( () => { + const { createBlock } = window.wp.blocks; + const { dispatch } = window.wp.data; + const blocks = window.lodash + .times( 1000 ) + .map( () => createBlock( 'core/paragraph' ) ); + dispatch( 'core/block-editor' ).resetBlocks( blocks ); + } ); + + const paragraphs = await page.$$( '.wp-block' ); + + await page.tracing.start( { + path: traceFile, + screenshots: false, + categories: [ 'devtools.timeline' ], + } ); + for ( let j = 0; j < 10; j++ ) { + await paragraphs[ j ].click(); + } + + await page.tracing.stop(); + + traceResults = JSON.parse( readFile( traceFile ) ); + const [ focusEvents ] = getSelectionEventDurations( traceResults ); + results.focus = focusEvents; + writeFileSync( __dirname + '/results.json', JSON.stringify( results, null, 2 ) diff --git a/packages/edit-navigation/.npmrc b/packages/edit-navigation/.npmrc new file mode 100644 index 00000000000000..43c97e719a5a82 --- /dev/null +++ b/packages/edit-navigation/.npmrc @@ -0,0 +1 @@ +package-lock=false diff --git a/packages/edit-navigation/README.md b/packages/edit-navigation/README.md new file mode 100644 index 00000000000000..b4df65e94c0ce4 --- /dev/null +++ b/packages/edit-navigation/README.md @@ -0,0 +1,5 @@ +- Package name +- Package description +- Installation details +- Usage example +- `Code is Poetry` logo (`<br/><br/><p align="center"><img src="https://s.w.org/style/images/codeispoetry.png?1" alt="Code is Poetry." /></p>`) diff --git a/packages/edit-navigation/package.json b/packages/edit-navigation/package.json new file mode 100644 index 00000000000000..65b58dfcbebdc1 --- /dev/null +++ b/packages/edit-navigation/package.json @@ -0,0 +1,46 @@ +{ + "name": "@wordpress/edit-navigation", + "version": "1.0.0-beta.2", + "private": true, + "description": "Module for the Navigation page in WordPress.", + "author": "The WordPress Contributors", + "license": "GPL-2.0-or-later", + "keywords": [ + "wordpress" + ], + "homepage": "https://github.com/WordPress/gutenberg/tree/master/packages/edit-navigation/README.md", + "repository": { + "type": "git", + "url": "https://github.com/WordPress/gutenberg.git", + "directory": "packages/edit-navigation" + }, + "bugs": { + "url": "https://github.com/WordPress/gutenberg/issues" + }, + "main": "build/index.js", + "module": "build-module/index.js", + "react-native": "src/index", + "dependencies": { + "@babel/runtime": "^7.9.2", + "@wordpress/block-editor": "file:../block-editor", + "@wordpress/block-library": "file:../block-library", + "@wordpress/blocks": "file:../blocks", + "@wordpress/components": "file:../components", + "@wordpress/compose": "file:../compose", + "@wordpress/data": "file:../data", + "@wordpress/data-controls": "file:../data-controls", + "@wordpress/dom-ready": "file:../dom-ready", + "@wordpress/element": "file:../element", + "@wordpress/hooks": "file:../hooks", + "@wordpress/i18n": "file:../i18n", + "@wordpress/keyboard-shortcuts": "file:../keyboard-shortcuts", + "@wordpress/media-utils": "file:../media-utils", + "@wordpress/notices": "file:../notices", + "classnames": "^2.2.5", + "lodash": "^4.17.15", + "rememo": "^3.0.0" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/edit-navigation/src/components/layout/index.js b/packages/edit-navigation/src/components/layout/index.js new file mode 100644 index 00000000000000..8459c6d45349f3 --- /dev/null +++ b/packages/edit-navigation/src/components/layout/index.js @@ -0,0 +1,60 @@ +/** + * WordPress dependencies + */ +import { + DropZoneProvider, + FocusReturnProvider, + Popover, + SlotFillProvider, + TabPanel, +} from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import MenusEditor from '../menus-editor'; +import MenuLocationsEditor from '../menu-locations-editor'; + +export default function Layout( { blockEditorSettings } ) { + return ( + <> + <SlotFillProvider> + <DropZoneProvider> + <FocusReturnProvider> + { /* <Notices /> */ } + <TabPanel + className="edit-navigation-layout__tab-panel" + tabs={ [ + { + name: 'menus', + title: __( 'Edit Navigation' ), + }, + { + name: 'menu-locations', + title: __( 'Manage Locations' ), + }, + ] } + > + { ( tab ) => ( + <> + { tab.name === 'menus' && ( + <MenusEditor + blockEditorSettings={ + blockEditorSettings + } + /> + ) } + { tab.name === 'menu-locations' && ( + <MenuLocationsEditor /> + ) } + </> + ) } + </TabPanel> + <Popover.Slot /> + </FocusReturnProvider> + </DropZoneProvider> + </SlotFillProvider> + </> + ); +} diff --git a/packages/edit-navigation/src/components/layout/style.scss b/packages/edit-navigation/src/components/layout/style.scss new file mode 100644 index 00000000000000..b533f3cd3b20a3 --- /dev/null +++ b/packages/edit-navigation/src/components/layout/style.scss @@ -0,0 +1,12 @@ +.edit-navigation-layout__tab-panel { + // Matches the padding-left applied by default to the `#wpcontent` element. + margin-right: 10px; + + @include break-medium { + margin-right: 20px; + } + + .components-tab-panel__tabs { + margin-bottom: 10px; + } +} diff --git a/packages/edit-navigation/src/components/menu-editor/block-editor-panel.js b/packages/edit-navigation/src/components/menu-editor/block-editor-panel.js new file mode 100644 index 00000000000000..3e1a2885b464d9 --- /dev/null +++ b/packages/edit-navigation/src/components/menu-editor/block-editor-panel.js @@ -0,0 +1,71 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + +/** + * WordPress dependencies + */ +import { + BlockList, + BlockToolbar, + NavigableToolbar, + ObserveTyping, + WritingFlow, +} from '@wordpress/block-editor'; +import { Button, Panel, PanelBody, Popover } from '@wordpress/components'; +import { useSelect } from '@wordpress/data'; +import { __ } from '@wordpress/i18n'; + +export default function BlockEditorPanel( { saveBlocks } ) { + const { isNavigationModeActive, hasSelectedBlock } = useSelect( + ( select ) => { + const { + isNavigationMode, + getBlockSelectionStart, + getBlock, + } = select( 'core/block-editor' ); + + const selectionStartClientId = getBlockSelectionStart(); + + return { + isNavigationModeActive: isNavigationMode(), + hasSelectedBlock: + !! selectionStartClientId && + !! getBlock( selectionStartClientId ), + }; + }, + [] + ); + + return ( + <Panel + className="edit-navigation-menu-editor__block-editor-panel" + header={ + <Button isPrimary onClick={ saveBlocks }> + { __( 'Save navigation' ) } + </Button> + } + > + <PanelBody title={ __( 'Navigation menu' ) }> + <NavigableToolbar + className={ classnames( + 'edit-navigation-menu-editor__block-editor-toolbar', + { + 'is-hidden': isNavigationModeActive, + } + ) } + aria-label={ __( 'Block tools' ) } + > + { hasSelectedBlock && <BlockToolbar hideDragHandle /> } + </NavigableToolbar> + <Popover.Slot name="block-toolbar" /> + <WritingFlow> + <ObserveTyping> + <BlockList /> + </ObserveTyping> + </WritingFlow> + </PanelBody> + </Panel> + ); +} diff --git a/packages/edit-navigation/src/components/menu-editor/index.js b/packages/edit-navigation/src/components/menu-editor/index.js new file mode 100644 index 00000000000000..3e8297bdf54038 --- /dev/null +++ b/packages/edit-navigation/src/components/menu-editor/index.js @@ -0,0 +1,47 @@ +/** + * WordPress dependencies + */ +import { + BlockEditorKeyboardShortcuts, + BlockEditorProvider, +} from '@wordpress/block-editor'; +import { useViewportMatch } from '@wordpress/compose'; + +/** + * Internal dependencies + */ +import useNavigationBlocks from './use-navigation-blocks'; +import MenuEditorShortcuts from './shortcuts'; +import BlockEditorPanel from './block-editor-panel'; +import NavigationStructurePanel from './navigation-structure-panel'; + +export default function MenuEditor( { menuId, blockEditorSettings } ) { + const [ blocks, setBlocks, saveBlocks ] = useNavigationBlocks( menuId ); + const isLargeViewport = useViewportMatch( 'medium' ); + + return ( + <div className="edit-navigation-menu-editor"> + <BlockEditorKeyboardShortcuts.Register /> + <MenuEditorShortcuts.Register /> + + <BlockEditorProvider + value={ blocks } + onInput={ ( updatedBlocks ) => setBlocks( updatedBlocks ) } + onChange={ ( updatedBlocks ) => setBlocks( updatedBlocks ) } + settings={ { + ...blockEditorSettings, + templateLock: 'all', + hasFixedToolbar: true, + } } + > + <BlockEditorKeyboardShortcuts /> + <MenuEditorShortcuts saveBlocks={ saveBlocks } /> + <NavigationStructurePanel + blocks={ blocks } + initialOpen={ isLargeViewport } + /> + <BlockEditorPanel saveBlocks={ saveBlocks } /> + </BlockEditorProvider> + </div> + ); +} diff --git a/packages/edit-navigation/src/components/menu-editor/navigation-structure-panel.js b/packages/edit-navigation/src/components/menu-editor/navigation-structure-panel.js new file mode 100644 index 00000000000000..147e894bcd95e1 --- /dev/null +++ b/packages/edit-navigation/src/components/menu-editor/navigation-structure-panel.js @@ -0,0 +1,27 @@ +/** + * WordPress dependencies + */ +import { __experimentalBlockNavigationList } from '@wordpress/block-editor'; +import { Panel, PanelBody } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; + +export default function NavigationStructurePanel( { blocks, initialOpen } ) { + return ( + <Panel className="edit-navigation-menu-editor__navigation-structure-panel"> + <PanelBody + title={ __( 'Navigation structure' ) } + initialOpen={ initialOpen } + > + { !! blocks.length && ( + <__experimentalBlockNavigationList + blocks={ blocks } + selectedBlockClientId={ blocks[ 0 ].clientId } + selectBlock={ () => {} } + showNestedBlocks + showAppender + /> + ) } + </PanelBody> + </Panel> + ); +} diff --git a/packages/edit-navigation/src/components/menu-editor/shortcuts.js b/packages/edit-navigation/src/components/menu-editor/shortcuts.js new file mode 100644 index 00000000000000..96889b67a8daa9 --- /dev/null +++ b/packages/edit-navigation/src/components/menu-editor/shortcuts.js @@ -0,0 +1,43 @@ +/** + * WordPress dependencies + */ +import { useEffect, useCallback } from '@wordpress/element'; +import { useDispatch } from '@wordpress/data'; +import { useShortcut } from '@wordpress/keyboard-shortcuts'; +import { __ } from '@wordpress/i18n'; + +function MenuEditorShortcuts( { saveBlocks } ) { + useShortcut( + 'core/edit-navigation/save-menu', + useCallback( ( event ) => { + event.preventDefault(); + saveBlocks(); + } ), + { + bindGlobal: true, + } + ); + + return null; +} + +function RegisterMenuEditorShortcuts() { + const { registerShortcut } = useDispatch( 'core/keyboard-shortcuts' ); + useEffect( () => { + registerShortcut( { + name: 'core/edit-navigation/save-menu', + category: 'global', + description: __( 'Save the menu currently being edited.' ), + keyCombination: { + modifier: 'primary', + character: 's', + }, + } ); + }, [ registerShortcut ] ); + + return null; +} + +MenuEditorShortcuts.Register = RegisterMenuEditorShortcuts; + +export default MenuEditorShortcuts; diff --git a/packages/edit-navigation/src/components/menu-editor/style.scss b/packages/edit-navigation/src/components/menu-editor/style.scss new file mode 100644 index 00000000000000..aa7a3d98b33f55 --- /dev/null +++ b/packages/edit-navigation/src/components/menu-editor/style.scss @@ -0,0 +1,68 @@ +.edit-navigation-menu-editor { + display: grid; + align-items: self-start; + grid-gap: 10px; + + @include break-medium { + grid-template-columns: 280px 1fr; + } + + // Make the block list take up the full width of the panel. + .block-editor-block-list__layout.is-root-container { + padding: 0; + } +} + +.edit-navigation-menu-editor__block-editor-toolbar { + height: 46px; + margin-bottom: 12px; + border: 1px solid #e2e4e7; + + // Borders around toolbar segments. + .components-toolbar { + background: none; + // IE11 has thick paddings without this. + line-height: 0; + + // These margins make the buttons themselves overlap the chrome of the toolbar. + // This helps make them square, and maximize the hit area. + margin-top: -$border-width; + margin-bottom: -$border-width; + + // The component is born with a border, but we only need some of them. + border: 0; + + // Add a border after item groups to show as separator in the block toolbar. + border-right: $border-width solid $light-gray-500; + } + + + // When entering navigation mode, hide the toolbar, but do so in a way where the + // outer container retains its height to avoid the blocks moving upwards. + &.is-hidden { + border-color: transparent; + + .block-editor-block-toolbar { + display: none; + } + } +} + +.edit-navigation-menu-editor__navigation-structure-panel { + // IE11 requires the column to be explicity declared. + grid-column: 1; + + // Make panels collapsible in IE. The IE analogue of align-items: self-start;. + -ms-grid-row-align: start; +} + +.edit-navigation-menu-editor__block-editor-panel { + @include break-medium { + // IE11 requires the column to be explicity declared. + // Only shift this into the second column on desktop. + grid-column: 2; + } + + // Make panels collapsible in IE. The IE analogue of align-items: self-start;. + -ms-grid-row-align: start; +} diff --git a/packages/edit-navigation/src/components/menu-editor/use-navigation-blocks.js b/packages/edit-navigation/src/components/menu-editor/use-navigation-blocks.js new file mode 100644 index 00000000000000..3dc27c54a7644d --- /dev/null +++ b/packages/edit-navigation/src/components/menu-editor/use-navigation-blocks.js @@ -0,0 +1,98 @@ +/** + * External dependencies + */ +import { isEqual, difference } from 'lodash'; + +/** + * WordPress dependencies + */ +import { createBlock } from '@wordpress/blocks'; +import { useSelect, useDispatch } from '@wordpress/data'; +import { useState, useRef, useEffect } from '@wordpress/element'; + +function createBlockFromMenuItem( menuItem ) { + return createBlock( 'core/navigation-link', { + label: menuItem.title.raw, + url: menuItem.url, + } ); +} + +function createMenuItemAttributesFromBlock( block ) { + return { + title: block.attributes.label, + url: block.attributes.url, + }; +} + +export default function useNavigationBlocks( menuId ) { + const menuItems = useSelect( + ( select ) => select( 'core' ).getMenuItems( { menus: menuId } ), + [ menuId ] + ); + + const { saveMenuItem } = useDispatch( 'core' ); + + const [ blocks, setBlocks ] = useState( [] ); + + const menuItemsRef = useRef( {} ); + + useEffect( () => { + if ( ! menuItems ) { + return; + } + + menuItemsRef.current = {}; + + const innerBlocks = []; + + for ( const menuItem of menuItems ) { + const block = createBlockFromMenuItem( menuItem ); + menuItemsRef.current[ block.clientId ] = menuItem; + innerBlocks.push( block ); + } + + setBlocks( [ createBlock( 'core/navigation', {}, innerBlocks ) ] ); + }, [ menuItems ] ); + + const saveBlocks = () => { + const { innerBlocks } = blocks[ 0 ]; + + for ( const block of innerBlocks ) { + const menuItem = menuItemsRef.current[ block.clientId ]; + + if ( ! menuItem ) { + saveMenuItem( { + ...createMenuItemAttributesFromBlock( block ), + menus: menuId, + } ); + continue; + } + + if ( + ! isEqual( + block.attributes, + createBlockFromMenuItem( menuItem ).attributes + ) + ) { + saveMenuItem( { + ...menuItem, + ...createMenuItemAttributesFromBlock( block ), + menus: menuId, // Gotta do this because REST API doesn't like receiving an array here. Maybe a bug in the REST API? + } ); + } + } + + const deletedClientIds = difference( + Object.keys( menuItemsRef.current ), + innerBlocks.map( ( block ) => block.clientId ) + ); + + // Disable reason, this code will eventually be implemented. + // eslint-disable-next-line no-unused-vars + for ( const clientId of deletedClientIds ) { + // TODO - delete menu items. + } + }; + + return [ blocks, setBlocks, saveBlocks ]; +} diff --git a/packages/edit-navigation/src/components/menu-locations-editor/index.js b/packages/edit-navigation/src/components/menu-locations-editor/index.js new file mode 100644 index 00000000000000..4d69195006cc74 --- /dev/null +++ b/packages/edit-navigation/src/components/menu-locations-editor/index.js @@ -0,0 +1,3 @@ +export default function MenuLocationsEditor() { + return <>Menu locations editor</>; +} diff --git a/packages/edit-navigation/src/components/menus-editor/index.js b/packages/edit-navigation/src/components/menus-editor/index.js new file mode 100644 index 00000000000000..b3513b1115044b --- /dev/null +++ b/packages/edit-navigation/src/components/menus-editor/index.js @@ -0,0 +1,54 @@ +/** + * WordPress dependencies + */ +import { useSelect } from '@wordpress/data'; +import { useState, useEffect } from '@wordpress/element'; +import { Card, CardBody, Spinner, SelectControl } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import MenuEditor from '../menu-editor'; + +export default function MenusEditor( { blockEditorSettings } ) { + const menus = useSelect( ( select ) => select( 'core' ).getMenus() ); + + const [ menuId, setMenuId ] = useState( 0 ); + + useEffect( () => { + if ( menus?.length ) { + setMenuId( menus[ 0 ].id ); + } + }, [ menus ] ); + + if ( ! menus ) { + return <Spinner />; + } + + return ( + <> + <Card className="edit-navigation-menus-editor__menu-selection-card"> + <CardBody> + <SelectControl + className="edit-navigation-menus-editor__menu-select-control" + label={ __( 'Select navigation to edit:' ) } + options={ menus.map( ( menu ) => ( { + value: menu.id, + label: menu.name, + } ) ) } + onChange={ ( selectedMenuId ) => + setMenuId( selectedMenuId ) + } + /> + </CardBody> + </Card> + { !! menuId && ( + <MenuEditor + menuId={ menuId } + blockEditorSettings={ blockEditorSettings } + /> + ) } + </> + ); +} diff --git a/packages/edit-navigation/src/components/menus-editor/style.scss b/packages/edit-navigation/src/components/menus-editor/style.scss new file mode 100644 index 00000000000000..8276863c97f964 --- /dev/null +++ b/packages/edit-navigation/src/components/menus-editor/style.scss @@ -0,0 +1,17 @@ +.edit-navigation-menus-editor__menu-selection-card { + margin-bottom: 10px; +} + +.edit-navigation-menus-editor__menu-select-control { + @include break-small { + .components-base-control__field { + display: flex; + flex-direction: row; + align-items: baseline; + margin-bottom: 0; + } + .components-base-control__label { + margin-right: 1ch; + } + } +} diff --git a/packages/edit-navigation/src/index.js b/packages/edit-navigation/src/index.js new file mode 100644 index 00000000000000..4d3b0005c00672 --- /dev/null +++ b/packages/edit-navigation/src/index.js @@ -0,0 +1,24 @@ +/** + * WordPress dependencies + */ +import { + registerCoreBlocks, + __experimentalRegisterExperimentalCoreBlocks, +} from '@wordpress/block-library'; +import { render } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import Layout from './components/layout'; + +export function initialize( id, settings ) { + registerCoreBlocks(); + if ( process.env.GUTENBERG_PHASE === 2 ) { + __experimentalRegisterExperimentalCoreBlocks( settings ); + } + render( + <Layout blockEditorSettings={ settings } />, + document.getElementById( id ) + ); +} diff --git a/packages/edit-navigation/src/style.scss b/packages/edit-navigation/src/style.scss new file mode 100644 index 00000000000000..1e907633b0724f --- /dev/null +++ b/packages/edit-navigation/src/style.scss @@ -0,0 +1,3 @@ +@import "./components/layout/style.scss"; +@import "./components/menu-editor/style.scss"; +@import "./components/menus-editor/style.scss"; diff --git a/packages/edit-post/README.md b/packages/edit-post/README.md index 641bb89209f185..5a1908b8cc05a9 100644 --- a/packages/edit-post/README.md +++ b/packages/edit-post/README.md @@ -438,10 +438,6 @@ _Parameters_ - _props.isPinnable_ `[boolean]`: Whether to allow to pin sidebar to toolbar. - _props.icon_ `[WPBlockTypeIconRender]`: The [Dashicon](https://developer.wordpress.org/resource/dashicons/) icon slug string, or an SVG WP element, to be rendered when the sidebar is pinned to toolbar. -_Returns_ - -- `WPComponent`: Plugin sidebar component. - <a name="PluginSidebarMoreMenuItem" href="#PluginSidebarMoreMenuItem">#</a> **PluginSidebarMoreMenuItem** Renders a menu item in `Plugins` group in `More Menu` drop down, diff --git a/packages/edit-post/package.json b/packages/edit-post/package.json index 8c0ef780a7f48a..153c5b771ef17b 100644 --- a/packages/edit-post/package.json +++ b/packages/edit-post/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/edit-post", - "version": "3.13.6", + "version": "3.15.1", "description": "Edit Post module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -21,7 +21,7 @@ "module": "build-module/index.js", "react-native": "src/index", "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/a11y": "file:../a11y", "@wordpress/api-fetch": "file:../api-fetch", "@wordpress/block-editor": "file:../block-editor", @@ -31,11 +31,13 @@ "@wordpress/compose": "file:../compose", "@wordpress/core-data": "file:../core-data", "@wordpress/data": "file:../data", + "@wordpress/data-controls": "file:../data-controls", "@wordpress/editor": "file:../editor", "@wordpress/element": "file:../element", "@wordpress/hooks": "file:../hooks", "@wordpress/i18n": "file:../i18n", "@wordpress/icons": "file:../icons", + "@wordpress/interface": "file:../interface", "@wordpress/keyboard-shortcuts": "file:../keyboard-shortcuts", "@wordpress/keycodes": "file:../keycodes", "@wordpress/media-utils": "file:../media-utils", @@ -46,7 +48,7 @@ "@wordpress/viewport": "file:../viewport", "classnames": "^2.2.5", "lodash": "^4.17.15", - "memize": "^1.0.5", + "memize": "^1.1.0", "refx": "^3.0.0", "rememo": "^3.0.0" }, diff --git a/packages/edit-post/src/components/block-settings-menu/plugin-block-settings-menu-item.js b/packages/edit-post/src/components/block-settings-menu/plugin-block-settings-menu-item.js index b23a62b33655a2..f87ddf23923e06 100644 --- a/packages/edit-post/src/components/block-settings-menu/plugin-block-settings-menu-item.js +++ b/packages/edit-post/src/components/block-settings-menu/plugin-block-settings-menu-item.js @@ -38,7 +38,8 @@ const shouldRenderItem = ( selectedBlocks, allowedBlocks ) => * @param {string} props.label The menu item text. * @param {Function} props.onClick Callback function to be executed when the user click the menu item. * - * @example <caption>ES5</caption> + * @example + * <caption>ES5</caption> * ```js * // Using ES5 syntax * var __ = wp.i18n.__; @@ -61,7 +62,8 @@ const shouldRenderItem = ( selectedBlocks, allowedBlocks ) => * } * ``` * - * @example <caption>ESNext</caption> + * @example + * <caption>ESNext</caption> * ```jsx * // Using ESNext syntax * import { __ } from wp.i18n; diff --git a/packages/edit-post/src/components/header/fullscreen-mode-close/index.js b/packages/edit-post/src/components/header/fullscreen-mode-close/index.js index 63869c6ac30b72..27cadc4f67b365 100644 --- a/packages/edit-post/src/components/header/fullscreen-mode-close/index.js +++ b/packages/edit-post/src/components/header/fullscreen-mode-close/index.js @@ -8,15 +8,9 @@ import { get } from 'lodash'; */ import { useSelect } from '@wordpress/data'; import { Button } from '@wordpress/components'; -import { Path, SVG } from '@wordpress/primitives'; import { __ } from '@wordpress/i18n'; import { addQueryArgs } from '@wordpress/url'; - -const wordPressLogo = ( - <SVG width="28" height="28" viewBox="0 0 128 128" version="1.1"> - <Path d="M100 61.3c0-6.6-2.4-11.2-4.4-14.7-2.7-4.4-5.2-8.1-5.2-12.5 0-4.9 3.7-9.5 9-9.5h.7c-9.5-8.7-22.1-14-36-14-18.6 0-35 9.6-44.6 24 1.3 0 2.4.1 3.4.1 5.6 0 14.2-.7 14.2-.7 2.9-.2 3.2 4.1.3 4.4 0 0-2.9.3-6.1.5l19.4 57.8 11.7-35L54.1 39c-2.9-.2-5.6-.5-5.6-.5-2.9-.2-2.5-4.6.3-4.4 0 0 8.8.7 14 .7 5.6 0 14.2-.7 14.2-.7 2.9-.2 3.2 4.1.3 4.4 0 0-2.9.3-6.1.5l19.3 57.3L96 78.9c2.6-7.6 4-13 4-17.6zM10.7 64c0 21.1 12.3 39.4 30.1 48L15.3 42.3c-3 6.6-4.6 14-4.6 21.7zm54.2 4.7l-16 46.5c4.8 1.4 9.8 2.2 15.1 2.2 6.2 0 12.2-1.1 17.7-3-.1-.2-.3-.5-.4-.7l-16.4-45zM64 0C28.7 0 0 28.7 0 64s28.7 64 64 64 64-28.7 64-64S99.3 0 64 0zm49.9 97.6c-2.2 3.2-4.6 6.2-7.3 8.9s-5.7 5.2-8.9 7.3c-3.2 2.2-6.7 4-10.2 5.5-7.4 3.1-15.3 4.7-23.4 4.7s-16-1.6-23.4-4.7c-3.6-1.5-7-3.4-10.2-5.5-3.2-2.2-6.2-4.6-8.9-7.3s-5.2-5.7-7.3-8.9c-2.2-3.2-4-6.7-5.5-10.2-3.4-7.4-5-15.3-5-23.4s1.6-16 4.7-23.4c1.5-3.6 3.4-7 5.5-10.2 2.2-3.2 4.6-6.2 7.3-8.9s5.7-5.2 8.9-7.3c3.2-2.2 6.7-4 10.2-5.5C48 5.4 55.9 3.8 64 3.8s16 1.6 23.4 4.7c3.6 1.5 7 3.4 10.2 5.5 3.2 2.2 6.2 4.6 8.9 7.3s5.2 5.7 7.3 8.9c2.2 3.2 4 6.7 5.5 10.2 3.1 7.4 4.7 15.3 4.7 23.4s-1.6 16-4.7 23.4c-1.4 3.8-3.2 7.2-5.4 10.4zm-2.7-53.7c0 5.4-1 11.5-4.1 19.1l-16.3 47.1c15.9-9.2 26.5-26.4 26.5-46.1 0-9.3-2.4-18-6.5-25.6.2 1.7.4 3.5.4 5.5z" /> - </SVG> -); +import { wordpress } from '@wordpress/icons'; function FullscreenModeClose() { const { isActive, postType } = useSelect( ( select ) => { @@ -37,7 +31,7 @@ function FullscreenModeClose() { return ( <Button className="edit-post-fullscreen-mode-close" - icon={ wordPressLogo } + icon={ wordpress } iconSize={ 36 } href={ addQueryArgs( 'edit.php', { post_type: postType.slug, diff --git a/packages/edit-post/src/components/header/fullscreen-mode-close/style.scss b/packages/edit-post/src/components/header/fullscreen-mode-close/style.scss index ad47bee1fb331f..2997e7745387b6 100644 --- a/packages/edit-post/src/components/header/fullscreen-mode-close/style.scss +++ b/packages/edit-post/src/components/header/fullscreen-mode-close/style.scss @@ -23,7 +23,7 @@ } &:focus { - box-shadow: inset 0 0 0 2px color($theme-color), inset 0 0 0 3px $white; + box-shadow: inset 0 0 0 $border-width-focus $theme-color, inset 0 0 0 ($border-width-focus + 1px) $white; } } } diff --git a/packages/edit-post/src/components/header/header-toolbar/index.js b/packages/edit-post/src/components/header/header-toolbar/index.js index 080f9e2c258257..4e386d22cc4f70 100644 --- a/packages/edit-post/src/components/header/header-toolbar/index.js +++ b/packages/edit-post/src/components/header/header-toolbar/index.js @@ -3,9 +3,8 @@ */ import { useViewportMatch } from '@wordpress/compose'; import { useSelect } from '@wordpress/data'; -import { __ } from '@wordpress/i18n'; +import { __, _x } from '@wordpress/i18n'; import { - Inserter, BlockToolbar, NavigableToolbar, BlockNavigationDropdown, @@ -16,13 +15,14 @@ import { EditorHistoryRedo, EditorHistoryUndo, } from '@wordpress/editor'; +import { Button } from '@wordpress/components'; +import { plus } from '@wordpress/icons'; -const inserterToggleProps = { isPrimary: true }; - -function HeaderToolbar() { +function HeaderToolbar( { onToggleInserter, isInserterOpen } ) { const { hasFixedToolbar, - showInserter, + isInserterEnabled, + isInserterVisible, isTextModeEnabled, previewDeviceType, } = useSelect( @@ -31,9 +31,10 @@ function HeaderToolbar() { 'fixedToolbar' ), // This setting (richEditingEnabled) should not live in the block editor's setting. - showInserter: + isInserterEnabled: select( 'core/edit-post' ).getEditorMode() === 'visual' && select( 'core/editor' ).getEditorSettings().richEditingEnabled, + isInserterVisible: select( 'core/block-editor' ).hasInserterItems(), isTextModeEnabled: select( 'core/edit-post' ).getEditorMode() === 'text', previewDeviceType: select( @@ -58,12 +59,20 @@ function HeaderToolbar() { className="edit-post-header-toolbar" aria-label={ toolbarAriaLabel } > - <Inserter - disabled={ ! showInserter } - position="bottom right" - showInserterHelpPanel - toggleProps={ inserterToggleProps } - /> + { isInserterVisible && ( + <Button + className="edit-post-header-toolbar__inserter-toggle" + isPrimary + isPressed={ isInserterOpen } + onClick={ onToggleInserter } + disabled={ ! isInserterEnabled } + icon={ plus } + label={ _x( + 'Add block', + 'Generic label for block inserter button' + ) } + /> + ) } <ToolSelector /> <EditorHistoryUndo /> <EditorHistoryRedo /> diff --git a/packages/edit-post/src/components/header/header-toolbar/index.native.js b/packages/edit-post/src/components/header/header-toolbar/index.native.js index 4e38926a1c4836..08c49b0c0d63ac 100644 --- a/packages/edit-post/src/components/header/header-toolbar/index.native.js +++ b/packages/edit-post/src/components/header/header-toolbar/index.native.js @@ -25,7 +25,6 @@ import { import styles from './style.scss'; function HeaderToolbar( { - hasFixedToolbar, hasRedo, hasUndo, redo, @@ -76,7 +75,7 @@ function HeaderToolbar( { hint: __( 'Double tap to redo last change' ), } } /> - { hasFixedToolbar && <BlockToolbar /> } + <BlockToolbar /> </ScrollView> { showKeyboardHideButton && ( <Toolbar passedStyle={ styles.keyboardHideContainer }> @@ -98,9 +97,6 @@ export default compose( [ withSelect( ( select ) => ( { hasRedo: select( 'core/editor' ).hasEditorRedo(), hasUndo: select( 'core/editor' ).hasEditorUndo(), - hasFixedToolbar: select( 'core/edit-post' ).isFeatureActive( - 'fixedToolbar' - ), // This setting (richEditingEnabled) should not live in the block editor's setting. showInserter: select( 'core/edit-post' ).getEditorMode() === 'visual' && diff --git a/packages/edit-post/src/components/header/header-toolbar/style.scss b/packages/edit-post/src/components/header/header-toolbar/style.scss index 95053f6808e137..ba3e478348f865 100644 --- a/packages/edit-post/src/components/header/header-toolbar/style.scss +++ b/packages/edit-post/src/components/header/header-toolbar/style.scss @@ -11,6 +11,10 @@ } } + > .edit-post-header-toolbar__inserter-toggle { + display: inline-flex; + } + // Hide table of contents and block navigation on mobile. .block-editor-block-navigation { display: none; @@ -75,3 +79,7 @@ } } } + +.edit-post-header-toolbar__inserter-toggle { + margin-right: $grid-unit-10; +} diff --git a/packages/edit-post/src/components/header/index.js b/packages/edit-post/src/components/header/index.js index 347a673d0ff2f3..c356909e9684fe 100644 --- a/packages/edit-post/src/components/header/index.js +++ b/packages/edit-post/src/components/header/index.js @@ -6,6 +6,7 @@ import { Button } from '@wordpress/components'; import { PostPreviewButton, PostSavedState } from '@wordpress/editor'; import { useSelect, useDispatch } from '@wordpress/data'; import { cog } from '@wordpress/icons'; +import { PinnedItems } from '@wordpress/interface'; /** * Internal dependencies @@ -13,11 +14,10 @@ import { cog } from '@wordpress/icons'; import FullscreenModeClose from './fullscreen-mode-close'; import HeaderToolbar from './header-toolbar'; import MoreMenu from './more-menu'; -import PinnedPlugins from './pinned-plugins'; import PostPublishButtonOrToggle from './post-publish-button-or-toggle'; import PreviewOptions from '../preview-options'; -function Header() { +function Header( { onToggleInserter, isInserterOpen } ) { const { shortcut, hasActiveMetaboxes, @@ -60,7 +60,10 @@ function Header() { <div className="edit-post-header"> <FullscreenModeClose /> <div className="edit-post-header__toolbar"> - <HeaderToolbar /> + <HeaderToolbar + onToggleInserter={ onToggleInserter } + isInserterOpen={ isInserterOpen } + /> </div> <div className="edit-post-header__settings"> { ! isPublishSidebarOpened && ( @@ -94,7 +97,7 @@ function Header() { aria-expanded={ isEditorSidebarOpened } shortcut={ shortcut } /> - <PinnedPlugins.Slot /> + <PinnedItems.Slot scope="core/edit-post" /> <MoreMenu /> </div> </div> diff --git a/packages/edit-post/src/components/header/index.native.js b/packages/edit-post/src/components/header/index.native.js index 727061f24aa465..787c35b527a2ab 100644 --- a/packages/edit-post/src/components/header/index.native.js +++ b/packages/edit-post/src/components/header/index.native.js @@ -7,6 +7,7 @@ import { Keyboard } from 'react-native'; * WordPress dependencies */ import { Component } from '@wordpress/element'; +import '@wordpress/interface'; /** * Internal dependencies diff --git a/packages/edit-post/src/components/header/mode-switcher/index.js b/packages/edit-post/src/components/header/mode-switcher/index.js index 78a522470f729a..5ee3ec93747978 100644 --- a/packages/edit-post/src/components/header/mode-switcher/index.js +++ b/packages/edit-post/src/components/header/mode-switcher/index.js @@ -42,6 +42,10 @@ function ModeSwitcher() { ); const { switchEditorMode } = useDispatch( 'core/edit-post' ); + if ( ! isRichEditingEnabled || ! isCodeEditingEnabled ) { + return null; + } + const choices = MODES.map( ( choice ) => { if ( choice.value !== mode ) { return { ...choice, shortcut }; @@ -49,10 +53,6 @@ function ModeSwitcher() { return choice; } ); - if ( ! isRichEditingEnabled || ! isCodeEditingEnabled ) { - return null; - } - return ( <MenuGroup label={ __( 'Editor' ) }> <MenuItemsChoice diff --git a/packages/edit-post/src/components/header/more-menu/test/__snapshots__/index.js.snap b/packages/edit-post/src/components/header/more-menu/test/__snapshots__/index.js.snap index 909241a36eaa02..9296591a638592 100644 --- a/packages/edit-post/src/components/header/more-menu/test/__snapshots__/index.js.snap +++ b/packages/edit-post/src/components/header/more-menu/test/__snapshots__/index.js.snap @@ -99,8 +99,8 @@ exports[`MoreMenu should match snapshot 1`] = ` xmlns="http://www.w3.org/2000/svg" > <svg - aria-hidden="true" - focusable="false" + aria-hidden={true} + focusable={false} height={24} role="img" viewBox="0 0 24 24" diff --git a/packages/edit-post/src/components/header/pinned-plugins/index.js b/packages/edit-post/src/components/header/pinned-plugins/index.js deleted file mode 100644 index 35f07ab0678d8b..00000000000000 --- a/packages/edit-post/src/components/header/pinned-plugins/index.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * External dependencies - */ -import { isEmpty } from 'lodash'; - -/** - * WordPress dependencies - */ -import { createSlotFill } from '@wordpress/components'; - -const { Fill: PinnedPlugins, Slot } = createSlotFill( 'PinnedPlugins' ); - -PinnedPlugins.Slot = ( props ) => ( - <Slot { ...props }> - { ( fills ) => - ! isEmpty( fills ) && ( - <div className="edit-post-pinned-plugins">{ fills }</div> - ) - } - </Slot> -); - -export default PinnedPlugins; diff --git a/packages/edit-post/src/components/header/pinned-plugins/style.scss b/packages/edit-post/src/components/header/pinned-plugins/style.scss deleted file mode 100644 index f8020c349699ad..00000000000000 --- a/packages/edit-post/src/components/header/pinned-plugins/style.scss +++ /dev/null @@ -1,45 +0,0 @@ -.edit-post-pinned-plugins { - display: none; - - @include break-small() { - display: flex; - } - - .components-button { - margin-left: 4px; - - &.is-pressed { - margin-left: 5px; - } - - svg { - max-width: 24px; - max-height: 24px; - } - } - - // Colorize plugin icons to ensure contrast and cohesion, but allow plugin developers to override. - .components-button:not(.is-pressed) svg, - .components-button:not(.is-pressed) svg * { - stroke: $dark-gray-primary; - fill: $dark-gray-primary; - stroke-width: 0; // !important is omitted here, so stroke-only icons can override easily. - } - - // Forcefully colorize hover and toggled plugin icon states to ensure legibility and consistency. - .components-button.is-pressed svg, - .components-button.is-pressed svg *, - .components-button.is-pressed:hover svg, - .components-button.is-pressed:hover svg * { - stroke: $white !important; - fill: $white !important; - stroke-width: 0; // !important is omitted here, so stroke-only icons can override easily. - } - - .components-button:hover svg, - .components-button:hover svg * { - stroke: $blue-medium-focus !important; - fill: $blue-medium-focus !important; - stroke-width: 0; // !important is omitted here, so stroke-only icons can override easily. - } -} diff --git a/packages/edit-post/src/components/header/plugin-more-menu-item/index.js b/packages/edit-post/src/components/header/plugin-more-menu-item/index.js index fa8d21caf7759b..ebcef732abeab4 100644 --- a/packages/edit-post/src/components/header/plugin-more-menu-item/index.js +++ b/packages/edit-post/src/components/header/plugin-more-menu-item/index.js @@ -36,7 +36,8 @@ const PluginMoreMenuItem = ( { onClick = noop, ...props } ) => ( * @param {Function} [props.onClick=noop] The callback function to be executed when the user clicks the menu item. * @param {...*} [props.other] Any additional props are passed through to the underlying [MenuItem](/packages/components/src/menu-item/README.md) component. * - * @example <caption>ES5</caption> + * @example + * <caption>ES5</caption> * ```js * // Using ES5 syntax * var __ = wp.i18n.__; @@ -59,7 +60,8 @@ const PluginMoreMenuItem = ( { onClick = noop, ...props } ) => ( * } * ``` * - * @example <caption>ESNext</caption> + * @example + * <caption>ESNext</caption> * ```jsx * // Using ESNext syntax * import { __ } from '@wordpress/i18n'; diff --git a/packages/edit-post/src/components/header/plugin-more-menu-item/test/__snapshots__/index.js.snap b/packages/edit-post/src/components/header/plugin-more-menu-item/test/__snapshots__/index.js.snap index d847aadaff72ca..44ebe7ba7b2138 100644 --- a/packages/edit-post/src/components/header/plugin-more-menu-item/test/__snapshots__/index.js.snap +++ b/packages/edit-post/src/components/header/plugin-more-menu-item/test/__snapshots__/index.js.snap @@ -22,9 +22,9 @@ exports[`PluginMoreMenuItem renders menu item as button properly 1`] = ` type="button" > <svg - aria-hidden="true" + aria-hidden={true} className="components-menu-items__item-icon" - focusable="false" + focusable={false} height={24} role="img" viewBox="0 0 24 24" diff --git a/packages/edit-post/src/components/header/plugin-sidebar-more-menu-item/index.js b/packages/edit-post/src/components/header/plugin-sidebar-more-menu-item/index.js index 2667a70f0d0f64..791f66dafaa580 100644 --- a/packages/edit-post/src/components/header/plugin-sidebar-more-menu-item/index.js +++ b/packages/edit-post/src/components/header/plugin-sidebar-more-menu-item/index.js @@ -36,7 +36,8 @@ const PluginSidebarMoreMenuItem = ( { * @param {string} props.target A string identifying the target sidebar you wish to be activated by this menu item. Must be the same as the `name` prop you have given to that sidebar. * @param {WPBlockTypeIconRender} [props.icon=inherits from the plugin] The [Dashicon](https://developer.wordpress.org/resource/dashicons/) icon slug string, or an SVG WP element, to be rendered to the left of the menu item label. * - * @example <caption>ES5</caption> + * @example + * <caption>ES5</caption> * ```js * // Using ES5 syntax * var __ = wp.i18n.__; @@ -55,7 +56,8 @@ const PluginSidebarMoreMenuItem = ( { * } * ``` * - * @example <caption>ESNext</caption> + * @example + * <caption>ESNext</caption> * ```jsx * // Using ESNext syntax * import { __ } from '@wordpress/i18n'; diff --git a/packages/edit-post/src/components/header/style.scss b/packages/edit-post/src/components/header/style.scss index 3ba75c71689c08..25b693ecb0bc81 100644 --- a/packages/edit-post/src/components/header/style.scss +++ b/packages/edit-post/src/components/header/style.scss @@ -64,24 +64,7 @@ /** * Buttons in the Toolbar */ - -.edit-post-header__toolbar { - .block-editor-inserter__toggle { - // Special dimensions for this button. - min-width: 32px; - height: 32px; - margin-right: $grid-unit-10; - } -} - - .edit-post-header__settings { - // Header toggle buttons. - .components-button.is-pressed { - color: $white; - background: $dark-gray-primary; - } - // Adjust button paddings to scale better to mobile. .components-button.editor-post-save-draft, .editor-post-saved-state, diff --git a/packages/edit-post/src/components/keyboard-shortcuts/index.js b/packages/edit-post/src/components/keyboard-shortcuts/index.js index e7bf499207b944..3e2e4938cc7f19 100644 --- a/packages/edit-post/src/components/keyboard-shortcuts/index.js +++ b/packages/edit-post/src/components/keyboard-shortcuts/index.js @@ -30,6 +30,7 @@ function KeyboardShortcuts() { switchEditorMode, openGeneralSidebar, closeGeneralSidebar, + toggleFeature, } = useDispatch( 'core/edit-post' ); const { registerShortcut } = useDispatch( 'core/keyboard-shortcuts' ); @@ -44,6 +45,16 @@ function KeyboardShortcuts() { }, } ); + registerShortcut( { + name: 'core/edit-post/toggle-fullscreen', + category: 'global', + description: __( 'Toggle fullscreen mode.' ), + keyCombination: { + modifier: 'secondary', + character: 'f', + }, + } ); + registerShortcut( { name: 'core/edit-post/toggle-block-navigation', category: 'global', @@ -120,6 +131,16 @@ function KeyboardShortcuts() { } ); + useShortcut( + 'core/edit-post/toggle-fullscreen', + () => { + toggleFeature( 'fullscreenMode' ); + }, + { + bindGlobal: true, + } + ); + useShortcut( 'core/edit-post/toggle-sidebar', ( event ) => { diff --git a/packages/edit-post/src/components/layout/index.js b/packages/edit-post/src/components/layout/index.js index 7ce59cf49882aa..c25ace812ff87c 100644 --- a/packages/edit-post/src/components/layout/index.js +++ b/packages/edit-post/src/components/layout/index.js @@ -17,8 +17,7 @@ import { import { useSelect, useDispatch } from '@wordpress/data'; import { BlockBreadcrumb, - __experimentalEditorSkeleton as EditorSkeleton, - __experimentalFullscreenMode as FullscreenMode, + __experimentalLibrary as Library, } from '@wordpress/block-editor'; import { Button, @@ -29,6 +28,13 @@ import { import { useViewportMatch } from '@wordpress/compose'; import { PluginArea } from '@wordpress/plugins'; import { __ } from '@wordpress/i18n'; +import { + ComplementaryArea, + FullscreenMode, + InterfaceSkeleton, +} from '@wordpress/interface'; +import { useState, useEffect } from '@wordpress/element'; +import { close } from '@wordpress/icons'; /** * Internal dependencies @@ -42,17 +48,23 @@ import OptionsModal from '../options-modal'; import BrowserURL from '../browser-url'; import Header from '../header'; import SettingsSidebar from '../sidebar/settings-sidebar'; -import Sidebar from '../sidebar'; import MetaBoxes from '../meta-boxes'; import PluginPostPublishPanel from '../sidebar/plugin-post-publish-panel'; import PluginPrePublishPanel from '../sidebar/plugin-pre-publish-panel'; import WelcomeGuide from '../welcome-guide'; +const interfaceLabels = { + leftSidebar: __( 'Block Library' ), +}; + function Layout() { + const [ isInserterOpen, setIsInserterOpen ] = useState( false ); const isMobileViewport = useViewportMatch( 'medium', '<' ); + const isHugeViewport = useViewportMatch( 'huge', '>=' ); const { closePublishSidebar, openGeneralSidebar, + closeGeneralSidebar, togglePublishSidebar, } = useDispatch( 'core/edit-post' ); const { @@ -112,6 +124,18 @@ function Layout() { hasBlockSelected ? 'edit-post/block' : 'edit-post/document' ); + // Inserter and Sidebars are mutually exclusive + useEffect( () => { + if ( sidebarIsOpened && ! isHugeViewport ) { + setIsInserterOpen( false ); + } + }, [ sidebarIsOpened, isHugeViewport ] ); + useEffect( () => { + if ( isInserterOpen && ! isHugeViewport ) { + closeGeneralSidebar(); + } + }, [ isInserterOpen, isHugeViewport ] ); + return ( <> <FullscreenMode isActive={ isFullscreenActive } /> @@ -122,9 +146,42 @@ function Layout() { <EditPostKeyboardShortcuts /> <EditorKeyboardShortcutsRegister /> <FocusReturnProvider> - <EditorSkeleton + <InterfaceSkeleton className={ className } - header={ <Header /> } + labels={ interfaceLabels } + header={ + <Header + isInserterOpen={ isInserterOpen } + onToggleInserter={ () => + setIsInserterOpen( ! isInserterOpen ) + } + /> + } + leftSidebar={ + mode === 'visual' && + isInserterOpen && ( + <div className="edit-post-layout__inserter-panel"> + <div className="edit-post-layout__inserter-panel-header"> + <Button + icon={ close } + onClick={ () => + setIsInserterOpen( false ) + } + /> + </div> + <div className="edit-post-layout__inserter-panel-content"> + <Library + showInserterHelpPanel + onSelect={ () => { + if ( isMobileViewport ) { + setIsInserterOpen( false ); + } + } } + /> + </div> + </div> + ) + } sidebar={ ( ! isMobileViewport || sidebarIsOpened ) && ( <> @@ -145,7 +202,7 @@ function Layout() { </div> ) } <SettingsSidebar /> - <Sidebar.Slot /> + <ComplementaryArea.Slot scope="core/edit-post" /> </> ) } @@ -176,7 +233,7 @@ function Layout() { </div> ) } - publish={ + actions={ publishSidebarOpened ? ( <PostPublishPanel onClose={ closePublishSidebar } diff --git a/packages/edit-post/src/components/layout/index.native.js b/packages/edit-post/src/components/layout/index.native.js index 6594d635a55e2c..eb989d7d4f32bd 100644 --- a/packages/edit-post/src/components/layout/index.native.js +++ b/packages/edit-post/src/components/layout/index.native.js @@ -12,7 +12,8 @@ import { withSelect } from '@wordpress/data'; import { BottomSheetSettings, __experimentalPageTemplatePicker, - __experimentalWithPageTemplatePickerVisible, + __experimentalWithPageTemplatePicker, + FloatingToolbar, } from '@wordpress/block-editor'; import { compose, withPreferredColorScheme } from '@wordpress/compose'; import { HTMLTextInput, KeyboardAvoidingView } from '@wordpress/components'; @@ -94,9 +95,10 @@ class Layout extends Component { render() { const { - mode, getStylesFromColorScheme, - showPageTemplatePicker, + isTemplatePickerAvailable, + isTemplatePickerVisible, + mode, } = this.props; const isHtmlView = mode === 'text'; @@ -130,6 +132,9 @@ class Layout extends Component { ) } > { isHtmlView ? this.renderHTML() : this.renderVisual() } + { ! isHtmlView && Platform.OS === 'android' && ( + <FloatingToolbar /> + ) } </View> <View style={ { @@ -143,9 +148,12 @@ class Layout extends Component { parentHeight={ this.state.rootViewHeight } style={ toolbarKeyboardAvoidingViewStyle } > - { showPageTemplatePicker && ( - <__experimentalPageTemplatePicker /> + { isTemplatePickerAvailable && ( + <__experimentalPageTemplatePicker + visible={ isTemplatePickerVisible } + /> ) } + { Platform.OS === 'ios' && <FloatingToolbar /> } <Header /> <BottomSheetSettings /> </KeyboardAvoidingView> @@ -168,5 +176,5 @@ export default compose( [ }; } ), withPreferredColorScheme, - __experimentalWithPageTemplatePickerVisible, + __experimentalWithPageTemplatePicker, ] )( Layout ); diff --git a/packages/edit-post/src/components/layout/style.scss b/packages/edit-post/src/components/layout/style.scss index 8a6df093381c39..340284a8613b15 100644 --- a/packages/edit-post/src/components/layout/style.scss +++ b/packages/edit-post/src/components/layout/style.scss @@ -15,7 +15,7 @@ .edit-post-layout .components-editor-notices__snackbar { position: fixed; right: 0; - bottom: 20px; + bottom: 40px; padding-left: 16px; padding-right: 16px; } @@ -57,7 +57,7 @@ } } -.block-editor-editor-skeleton__sidebar > div { +.interface-interface-skeleton__sidebar > div { height: 100%; } @@ -82,10 +82,10 @@ display: flex; justify-content: center; - .block-editor-editor-skeleton__publish:focus &, - .block-editor-editor-skeleton__publish:focus-within &, - .block-editor-editor-skeleton__sidebar:focus &, - .block-editor-editor-skeleton__sidebar:focus-within & { + .interface-interface-skeleton__actions:focus &, + .interface-interface-skeleton__actions:focus-within &, + .interface-interface-skeleton__actions:focus &, + .interface-interface-skeleton__actions:focus-within & { top: auto; bottom: 0; } @@ -106,7 +106,32 @@ } } -.edit-post-layout .block-editor-editor-skeleton__content { +.edit-post-layout .interface-interface-skeleton__content { background-color: $light-gray-700; } +.edit-post-layout__inserter-panel { + height: 100%; + display: flex; + flex-direction: column; +} + +.edit-post-layout__inserter-panel-header { + padding-top: $grid-unit-10; + padding-right: $grid-unit-10; + display: flex; + justify-content: flex-end; + + @include break-medium() { + display: none; + } +} + +.edit-post-layout__inserter-panel-content { + // Leave space for the close button + height: calc(100% - #{$button-size} - #{$grid-unit-10}); + + @include break-medium() { + height: 100%; + } +} diff --git a/packages/edit-post/src/components/manage-blocks-modal/manager.js b/packages/edit-post/src/components/manage-blocks-modal/manager.js index bdb8349be888f7..41eba0b4f97e9a 100644 --- a/packages/edit-post/src/components/manage-blocks-modal/manager.js +++ b/packages/edit-post/src/components/manage-blocks-modal/manager.js @@ -52,9 +52,10 @@ function BlockManager( { { !! numberOfHiddenBlocks && ( <div className="edit-post-manage-blocks-modal__disabled-blocks-count"> { sprintf( + /* translators: %d: number of blocks. */ _n( - '%1$d block is disabled.', - '%1$d blocks are disabled.', + '%d block is disabled.', + '%d blocks are disabled.', numberOfHiddenBlocks ), numberOfHiddenBlocks diff --git a/packages/edit-post/src/components/options-modal/options/test/__snapshots__/enable-custom-fields.js.snap b/packages/edit-post/src/components/options-modal/options/test/__snapshots__/enable-custom-fields.js.snap index fd30201bd3b8d6..eb27081e91dc8f 100644 --- a/packages/edit-post/src/components/options-modal/options/test/__snapshots__/enable-custom-fields.js.snap +++ b/packages/edit-post/src/components/options-modal/options/test/__snapshots__/enable-custom-fields.js.snap @@ -22,9 +22,9 @@ exports[`EnableCustomFieldsOption renders a checked checkbox and a confirmation value="1" /> <svg - aria-hidden="true" + aria-hidden={true} className="components-checkbox-control__checked" - focusable="false" + focusable={false} height={24} role="img" viewBox="0 0 24 24" @@ -80,9 +80,9 @@ exports[`EnableCustomFieldsOption renders a checked checkbox when custom fields value="1" /> <svg - aria-hidden="true" + aria-hidden={true} className="components-checkbox-control__checked" - focusable="false" + focusable={false} height={24} role="img" viewBox="0 0 24 24" diff --git a/packages/edit-post/src/components/preview-options/style.scss b/packages/edit-post/src/components/preview-options/style.scss index d56693cfa1adad..de88a83faa7b2b 100644 --- a/packages/edit-post/src/components/preview-options/style.scss +++ b/packages/edit-post/src/components/preview-options/style.scss @@ -10,7 +10,7 @@ padding: 0 $grid-unit-10 0 $grid-unit-15; &:focus:not(:disabled) { - box-shadow: inset 0 0 0 1px $white, 0 0 0 2px color($theme-color); + box-shadow: inset 0 0 0 1px $white, 0 0 0 $border-width-focus $theme-color; } svg { diff --git a/packages/edit-post/src/components/sidebar/index.js b/packages/edit-post/src/components/sidebar/index.js deleted file mode 100644 index e6175b72b2685a..00000000000000 --- a/packages/edit-post/src/components/sidebar/index.js +++ /dev/null @@ -1,64 +0,0 @@ -/** - * External dependencies - */ -import classnames from 'classnames'; - -/** - * WordPress dependencies - */ -import { - createSlotFill, - withFocusReturn, - Animate, -} from '@wordpress/components'; -import { withSelect } from '@wordpress/data'; -import { ifCondition, compose } from '@wordpress/compose'; - -const { Fill, Slot } = createSlotFill( 'Sidebar' ); - -/** - * Renders a sidebar with its content. - * - * @return {Object} The rendered sidebar. - */ -function Sidebar( { children, className } ) { - return ( - <div className={ classnames( 'edit-post-sidebar', className ) }> - { children } - </div> - ); -} - -Sidebar = withFocusReturn( { - onFocusReturn() { - const button = document.querySelector( - '.edit-post-header__settings [aria-label="Settings"]' - ); - if ( button ) { - button.focus(); - return false; - } - }, -} )( Sidebar ); - -function AnimatedSidebarFill( props ) { - return ( - <Fill> - <Animate type="slide-in" options={ { origin: 'left' } }> - { () => <Sidebar { ...props } /> } - </Animate> - </Fill> - ); -} - -const WrappedSidebar = compose( - withSelect( ( select, { name } ) => ( { - isActive: - select( 'core/edit-post' ).getActiveGeneralSidebarName() === name, - } ) ), - ifCondition( ( { isActive } ) => isActive ) -)( AnimatedSidebarFill ); - -WrappedSidebar.Slot = Slot; - -export default WrappedSidebar; diff --git a/packages/edit-post/src/components/sidebar/plugin-document-setting-panel/index.js b/packages/edit-post/src/components/sidebar/plugin-document-setting-panel/index.js index 757e4965e5d991..56133e8162aad6 100644 --- a/packages/edit-post/src/components/sidebar/plugin-document-setting-panel/index.js +++ b/packages/edit-post/src/components/sidebar/plugin-document-setting-panel/index.js @@ -59,7 +59,8 @@ const PluginDocumentSettingFill = ( { * @param {string} [props.title] The title of the panel * @param {WPBlockTypeIconRender} [props.icon=inherits from the plugin] The [Dashicon](https://developer.wordpress.org/resource/dashicons/) icon slug string, or an SVG WP element, to be rendered when the sidebar is pinned to toolbar. * - * @example <caption>ES5</caption> + * @example + * <caption>ES5</caption> * ```js * // Using ES5 syntax * var el = wp.element.createElement; @@ -83,7 +84,8 @@ const PluginDocumentSettingFill = ( { * } ); * ``` * - * @example <caption>ESNext</caption> + * @example + * <caption>ESNext</caption> * ```jsx * // Using ESNext syntax * const { registerPlugin } = wp.plugins; diff --git a/packages/edit-post/src/components/sidebar/plugin-post-publish-panel/index.js b/packages/edit-post/src/components/sidebar/plugin-post-publish-panel/index.js index 43d1fc2d1eaac4..73fabe8a32f48b 100644 --- a/packages/edit-post/src/components/sidebar/plugin-post-publish-panel/index.js +++ b/packages/edit-post/src/components/sidebar/plugin-post-publish-panel/index.js @@ -35,7 +35,8 @@ const PluginPostPublishPanelFill = ( { * @param {boolean} [props.initialOpen=false] Whether to have the panel initially opened. When no title is provided it is always opened. * @param {WPBlockTypeIconRender} [props.icon=inherits from the plugin] The [Dashicon](https://developer.wordpress.org/resource/dashicons/) icon slug string, or an SVG WP element, to be rendered when the sidebar is pinned to toolbar. * - * @example <caption>ES5</caption> + * @example + * <caption>ES5</caption> * ```js * // Using ES5 syntax * var __ = wp.i18n.__; @@ -54,7 +55,8 @@ const PluginPostPublishPanelFill = ( { * } * ``` * - * @example <caption>ESNext</caption> + * @example + * <caption>ESNext</caption> * ```jsx * // Using ESNext syntax * const { __ } = wp.i18n; diff --git a/packages/edit-post/src/components/sidebar/plugin-post-status-info/index.js b/packages/edit-post/src/components/sidebar/plugin-post-status-info/index.js index 10259358e764f9..b43199112901b1 100644 --- a/packages/edit-post/src/components/sidebar/plugin-post-status-info/index.js +++ b/packages/edit-post/src/components/sidebar/plugin-post-status-info/index.js @@ -17,7 +17,8 @@ export const { Fill, Slot } = createSlotFill( 'PluginPostStatusInfo' ); * @param {Object} props Component properties. * @param {string} [props.className] An optional class name added to the row. * - * @example <caption>ES5</caption> + * @example + * <caption>ES5</caption> * ```js * // Using ES5 syntax * var __ = wp.i18n.__; @@ -34,7 +35,8 @@ export const { Fill, Slot } = createSlotFill( 'PluginPostStatusInfo' ); * } * ``` * - * @example <caption>ESNext</caption> + * @example + * <caption>ESNext</caption> * ```jsx * // Using ESNext syntax * const { __ } = wp.i18n; diff --git a/packages/edit-post/src/components/sidebar/plugin-pre-publish-panel/index.js b/packages/edit-post/src/components/sidebar/plugin-pre-publish-panel/index.js index db6900995db37d..8f39c8e1ee5313 100644 --- a/packages/edit-post/src/components/sidebar/plugin-pre-publish-panel/index.js +++ b/packages/edit-post/src/components/sidebar/plugin-pre-publish-panel/index.js @@ -38,7 +38,8 @@ const PluginPrePublishPanelFill = ( { * icon slug string, or an SVG WP element, to be rendered when * the sidebar is pinned to toolbar. * - * @example <caption>ES5</caption> + * @example + * <caption>ES5</caption> * ```js * // Using ES5 syntax * var __ = wp.i18n.__; @@ -57,7 +58,8 @@ const PluginPrePublishPanelFill = ( { * } * ``` * - * @example <caption>ESNext</caption> + * @example + * <caption>ESNext</caption> * ```jsx * // Using ESNext syntax * const { __ } = wp.i18n; diff --git a/packages/edit-post/src/components/sidebar/plugin-sidebar/index.js b/packages/edit-post/src/components/sidebar/plugin-sidebar/index.js index deb007a37d82dc..3034d5bab9165f 100644 --- a/packages/edit-post/src/components/sidebar/plugin-sidebar/index.js +++ b/packages/edit-post/src/components/sidebar/plugin-sidebar/index.js @@ -1,71 +1,9 @@ /** * WordPress dependencies */ -import { Button, Panel } from '@wordpress/components'; -import { withDispatch, withSelect } from '@wordpress/data'; +import { ComplementaryArea } from '@wordpress/interface'; +import { useSelect } from '@wordpress/data'; import { __ } from '@wordpress/i18n'; -import { withPluginContext } from '@wordpress/plugins'; -import { compose } from '@wordpress/compose'; -import { starEmpty, starFilled } from '@wordpress/icons'; - -/** - * Internal dependencies - */ -import PinnedPlugins from '../../header/pinned-plugins'; -import Sidebar from '../'; -import SidebarHeader from '../sidebar-header'; - -function PluginSidebar( props ) { - const { - children, - className, - icon, - isActive, - isPinnable = true, - isPinned, - sidebarName, - title, - togglePin, - toggleSidebar, - } = props; - - return ( - <> - { isPinnable && ( - <PinnedPlugins> - { isPinned && ( - <Button - icon={ icon } - label={ title } - onClick={ toggleSidebar } - isPressed={ isActive } - aria-expanded={ isActive } - /> - ) } - </PinnedPlugins> - ) } - <Sidebar name={ sidebarName }> - <SidebarHeader closeLabel={ __( 'Close plugin' ) }> - <strong>{ title }</strong> - { isPinnable && ( - <Button - icon={ isPinned ? starFilled : starEmpty } - label={ - isPinned - ? __( 'Unpin from toolbar' ) - : __( 'Pin to toolbar' ) - } - onClick={ togglePin } - isPressed={ isPinned } - aria-expanded={ isPinned } - /> - ) } - </SidebarHeader> - <Panel className={ className }>{ children }</Panel> - </Sidebar> - </> - ); -} /** * Renders a sidebar when activated. The contents within the `PluginSidebar` will appear as content within the sidebar. @@ -84,7 +22,8 @@ function PluginSidebar( props ) { * @param {boolean} [props.isPinnable=true] Whether to allow to pin sidebar to toolbar. * @param {WPBlockTypeIconRender} [props.icon=inherits from the plugin] The [Dashicon](https://developer.wordpress.org/resource/dashicons/) icon slug string, or an SVG WP element, to be rendered when the sidebar is pinned to toolbar. * - * @example <caption>ES5</caption> + * @example + * <caption>ES5</caption> * ```js * // Using ES5 syntax * var __ = wp.i18n.__; @@ -110,7 +49,8 @@ function PluginSidebar( props ) { * } * ``` * - * @example <caption>ESNext</caption> + * @example + * <caption>ESNext</caption> * ```jsx * // Using ESNext syntax * import { __ } from '@wordpress/i18n'; @@ -130,44 +70,26 @@ function PluginSidebar( props ) { * </PluginSidebar> * ); * ``` - * - * @return {WPComponent} Plugin sidebar component. */ -export default compose( - withPluginContext( ( context, ownProps ) => { +export default function PluginSidebarEditPost( { className, ...props } ) { + const { postTitle, shortcut } = useSelect( ( select ) => { return { - icon: ownProps.icon || context.icon, - sidebarName: `${ context.name }/${ ownProps.name }`, + postTitle: select( 'core/editor' ).getEditedPostAttribute( + 'title' + ), + shortcut: select( + 'core/keyboard-shortcuts' + ).getShortcutRepresentation( 'core/edit-post/toggle-sidebar' ), }; - } ), - withSelect( ( select, { sidebarName } ) => { - const { getActiveGeneralSidebarName, isPluginItemPinned } = select( - 'core/edit-post' - ); - - return { - isActive: getActiveGeneralSidebarName() === sidebarName, - isPinned: isPluginItemPinned( sidebarName ), - }; - } ), - withDispatch( ( dispatch, { isActive, sidebarName } ) => { - const { - closeGeneralSidebar, - openGeneralSidebar, - togglePinnedPluginItem, - } = dispatch( 'core/edit-post' ); - - return { - togglePin() { - togglePinnedPluginItem( sidebarName ); - }, - toggleSidebar() { - if ( isActive ) { - closeGeneralSidebar(); - } else { - openGeneralSidebar( sidebarName ); - } - }, - }; - } ) -)( PluginSidebar ); + } ); + return ( + <ComplementaryArea + panelClassName={ className } + className="edit-post-sidebar" + smallScreenTitle={ postTitle || __( '(no title)' ) } + scope="core/edit-post" + toggleShortcut={ shortcut } + { ...props } + /> + ); +} diff --git a/packages/edit-post/src/components/sidebar/post-link/index.js b/packages/edit-post/src/components/sidebar/post-link/index.js index e8f7f6008b27d2..5bf5b6bba6997b 100644 --- a/packages/edit-post/src/components/sidebar/post-link/index.js +++ b/packages/edit-post/src/components/sidebar/post-link/index.js @@ -94,9 +94,9 @@ function PostLink( { </p> </div> ) } - <p className="edit-post-post-link__preview-label"> + <h3 className="edit-post-post-link__preview-label"> { postTypeLabel || __( 'View post' ) } - </p> + </h3> <div className="edit-post-post-link__preview-link-container"> <ExternalLink className="edit-post-post-link__link" diff --git a/packages/edit-post/src/components/sidebar/post-link/style.scss b/packages/edit-post/src/components/sidebar/post-link/style.scss index efe6ecce4af395..ab442190b61e61 100644 --- a/packages/edit-post/src/components/sidebar/post-link/style.scss +++ b/packages/edit-post/src/components/sidebar/post-link/style.scss @@ -3,6 +3,7 @@ } .edit-post-post-link__preview-label { + font-weight: 400; margin: 0; } diff --git a/packages/edit-post/src/components/sidebar/settings-header/index.js b/packages/edit-post/src/components/sidebar/settings-header/index.js index 4f2a2d4ebe9ff2..b4317b9217906f 100644 --- a/packages/edit-post/src/components/sidebar/settings-header/index.js +++ b/packages/edit-post/src/components/sidebar/settings-header/index.js @@ -5,11 +5,6 @@ import { Button } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { withDispatch } from '@wordpress/data'; -/** - * Internal dependencies - */ -import SidebarHeader from '../sidebar-header'; - const SettingsHeader = ( { openDocumentSettings, openBlockSettings, @@ -30,35 +25,30 @@ const SettingsHeader = ( { : // translators: ARIA label for the Settings Sidebar tab, not selected. [ __( 'Block' ), '' ]; + /* Use a list so screen readers will announce how many tabs there are. */ return ( - <SidebarHeader - className="edit-post-sidebar__panel-tabs" - closeLabel={ __( 'Close settings' ) } - > - { /* Use a list so screen readers will announce how many tabs there are. */ } - <ul> - <li> - <Button - onClick={ openDocumentSettings } - className={ `edit-post-sidebar__panel-tab ${ documentActiveClass }` } - aria-label={ documentAriaLabel } - data-label={ __( 'Document' ) } - > - { __( 'Document' ) } - </Button> - </li> - <li> - <Button - onClick={ openBlockSettings } - className={ `edit-post-sidebar__panel-tab ${ blockActiveClass }` } - aria-label={ blockAriaLabel } - data-label={ blockLabel } - > - { blockLabel } - </Button> - </li> - </ul> - </SidebarHeader> + <ul> + <li> + <Button + onClick={ openDocumentSettings } + className={ `edit-post-sidebar__panel-tab ${ documentActiveClass }` } + aria-label={ documentAriaLabel } + data-label={ __( 'Document' ) } + > + { __( 'Document' ) } + </Button> + </li> + <li> + <Button + onClick={ openBlockSettings } + className={ `edit-post-sidebar__panel-tab ${ blockActiveClass }` } + aria-label={ blockAriaLabel } + data-label={ blockLabel } + > + { blockLabel } + </Button> + </li> + </ul> ); }; diff --git a/packages/edit-post/src/components/sidebar/settings-header/style.scss b/packages/edit-post/src/components/sidebar/settings-header/style.scss index 5411341b547e3c..04684bc06b4232 100644 --- a/packages/edit-post/src/components/sidebar/settings-header/style.scss +++ b/packages/edit-post/src/components/sidebar/settings-header/style.scss @@ -13,6 +13,8 @@ } .components-button.edit-post-sidebar__panel-tab { + border-radius: 0; + height: 50px - $border-width; background: transparent; border: none; box-shadow: none; @@ -22,9 +24,6 @@ margin-left: 0; font-weight: 400; color: $dark-gray-900; - @include square-style__neutral; - transition: box-shadow 0.1s linear; - @include reduce-motion("transition"); // This pseudo-element "duplicates" the tab label and sets the text to bold. // This ensures that the tab doesn't change width when selected. @@ -40,7 +39,8 @@ } &.is-active { - box-shadow: inset 0 -4px theme(outlines); + // The transparent shadow ensures no jumpiness when focus animates on an active tab. + box-shadow: inset 0 0 0 $border-width-focus transparent, inset 0 0 -$border-width-tab 0 0 $theme-color; font-weight: 600; position: relative; @@ -52,12 +52,15 @@ bottom: 1px; right: 0; left: 0; - border-bottom: 4px solid transparent; + border-bottom: $border-width-tab solid transparent; } } &:focus { - background-color: transparent; - @include square-style__focus; + box-shadow: inset 0 0 0 $border-width-focus $theme-color; + } + + &.is-active:focus { + box-shadow: inset 0 0 0 $border-width-focus $theme-color, inset 0 0 -$border-width-tab 0 0 $theme-color; } } diff --git a/packages/edit-post/src/components/sidebar/settings-sidebar/index.js b/packages/edit-post/src/components/sidebar/settings-sidebar/index.js index df162808e438d5..befb270be4f668 100644 --- a/packages/edit-post/src/components/sidebar/settings-sidebar/index.js +++ b/packages/edit-post/src/components/sidebar/settings-sidebar/index.js @@ -1,15 +1,11 @@ /** * WordPress dependencies */ -import { Panel } from '@wordpress/components'; -import { compose, ifCondition } from '@wordpress/compose'; -import { withSelect } from '@wordpress/data'; import { BlockInspector } from '@wordpress/block-editor'; /** * Internal dependencies */ -import Sidebar from '../'; import SettingsHeader from '../settings-header'; import PostStatus from '../post-status'; import LastRevision from '../last-revision'; @@ -21,11 +17,31 @@ import DiscussionPanel from '../discussion-panel'; import PageAttributes from '../page-attributes'; import MetaBoxes from '../../meta-boxes'; import PluginDocumentSettingPanel from '../plugin-document-setting-panel'; +import PluginSidebarEditPost from '../../sidebar/plugin-sidebar'; +import { __ } from '@wordpress/i18n'; +import { useSelect } from '@wordpress/data'; -const SettingsSidebar = ( { sidebarName } ) => ( - <Sidebar name={ sidebarName }> - <SettingsHeader sidebarName={ sidebarName } /> - <Panel> +const SettingsSidebar = () => { + const sidebarName = useSelect( + ( select ) => + select( 'core/interface' ).getActiveComplementaryArea( + 'core/edit-post' + ), + [] + ); + if ( + ! [ 'edit-post/document', 'edit-post/block' ].includes( sidebarName ) + ) { + return null; + } + return ( + <PluginSidebarEditPost + complementaryAreaIdentifier={ sidebarName } + header={ <SettingsHeader sidebarName={ sidebarName } /> } + closeLabel={ __( 'Close settings' ) } + headerClassName="edit-post-sidebar__panel-tabs" + isPinnable={ false } + > { sidebarName === 'edit-post/document' && ( <> <PostStatus /> @@ -41,20 +57,8 @@ const SettingsSidebar = ( { sidebarName } ) => ( </> ) } { sidebarName === 'edit-post/block' && <BlockInspector /> } - </Panel> - </Sidebar> -); + </PluginSidebarEditPost> + ); +}; -export default compose( - withSelect( ( select ) => { - const { getActiveGeneralSidebarName, isEditorSidebarOpened } = select( - 'core/edit-post' - ); - - return { - isEditorSidebarOpened: isEditorSidebarOpened(), - sidebarName: getActiveGeneralSidebarName(), - }; - } ), - ifCondition( ( { isEditorSidebarOpened } ) => isEditorSidebarOpened ) -)( SettingsSidebar ); +export default SettingsSidebar; diff --git a/packages/edit-post/src/components/sidebar/sidebar-header/index.js b/packages/edit-post/src/components/sidebar/sidebar-header/index.js deleted file mode 100644 index 84bd69b07e7048..00000000000000 --- a/packages/edit-post/src/components/sidebar/sidebar-header/index.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * External dependencies - */ -import classnames from 'classnames'; - -/** - * WordPress dependencies - */ -import { __ } from '@wordpress/i18n'; -import { Button } from '@wordpress/components'; -import { useDispatch, useSelect } from '@wordpress/data'; -import { close } from '@wordpress/icons'; - -const SidebarHeader = ( { children, className, closeLabel } ) => { - const { shortcut, title } = useSelect( - ( select ) => ( { - shortcut: select( - 'core/keyboard-shortcuts' - ).getShortcutRepresentation( 'core/edit-post/toggle-sidebar' ), - title: select( 'core/editor' ).getEditedPostAttribute( 'title' ), - } ), - [] - ); - const { closeGeneralSidebar } = useDispatch( 'core/edit-post' ); - - return ( - <> - <div className="components-panel__header edit-post-sidebar-header__small"> - <span className="edit-post-sidebar-header__title"> - { title || __( '(no title)' ) } - </span> - <Button - onClick={ closeGeneralSidebar } - icon={ close } - label={ closeLabel } - /> - </div> - <div - className={ classnames( - 'components-panel__header edit-post-sidebar-header', - className - ) } - > - { children } - <Button - onClick={ closeGeneralSidebar } - icon={ close } - label={ closeLabel } - shortcut={ shortcut } - /> - </div> - </> - ); -}; - -export default SidebarHeader; diff --git a/packages/edit-post/src/components/sidebar/style.scss b/packages/edit-post/src/components/sidebar/style.scss index f960c6757c3033..d3be8c5f30caa5 100644 --- a/packages/edit-post/src/components/sidebar/style.scss +++ b/packages/edit-post/src/components/sidebar/style.scss @@ -1,107 +1,3 @@ -.edit-post-sidebar { - background: $white; - color: $dark-gray-500; - overflow: visible; - - @include break-small() { - z-index: auto; - height: 100%; - overflow: auto; - -webkit-overflow-scrolling: touch; - } - - @include break-medium() { - width: $sidebar-width; - } - - > .components-panel { - border-left: none; - border-right: none; - overflow: auto; - -webkit-overflow-scrolling: touch; - height: auto; - max-height: calc(100vh - #{ $admin-bar-height-big + $panel-header-height + $panel-header-height }); - margin-top: -1px; - margin-bottom: -1px; - position: relative; - - @include break-small() { - overflow: visible; - height: auto; - max-height: none; - } - } - - > .components-panel .components-panel__header { - position: fixed; - z-index: z-index(".components-panel__header"); - top: 0; - left: 0; - right: 0; - height: $panel-header-height; - - @include break-small() { - position: inherit; - top: auto; - left: auto; - right: auto; - } - } - - p { - margin-top: 0; - } - - h2, - h3 { - font-size: $default-font-size; - color: $dark-gray-500; - margin-bottom: 1.5em; - } - - hr { - border-top: none; - border-bottom: 1px solid $light-gray-500; - margin: 1.5em 0; - } - - div.components-toolbar { - box-shadow: none; - margin-bottom: 1.5em; - &:last-child { - margin-bottom: 0; - } - } - - p + div.components-toolbar { - margin-top: -1em; - } - - .block-editor-skip-to-selected-block:focus { - top: auto; - right: 10px; - bottom: 10px; - left: auto; - } -} - -/* Text Editor specific */ -.components-panel__header.edit-post-sidebar__header { - background: $white; - padding-right: $panel-padding / 2; - - .edit-post-sidebar__title { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - width: 100%; - } - - @include break-medium() { - display: none; - } -} - .components-panel__header.edit-post-sidebar__panel-tabs { justify-content: flex-start; padding-left: 0; @@ -118,40 +14,3 @@ } } } - -.edit-post-sidebar__panel-tab { - background: transparent; - border: none; - border-radius: 0; - box-shadow: none; - cursor: pointer; - height: 50px; - padding: 3px 15px; // Use padding to offset the is-active border, this benefits Windows High Contrast mode - margin-left: 0; - font-weight: 400; - @include square-style__neutral; - transition: box-shadow 0.1s linear; - @include reduce-motion("transition"); - - &.is-active { - box-shadow: inset 0 -3px theme(outlines); - font-weight: 600; - position: relative; - - // This border appears in Windows High Contrast mode instead of the box-shadow. - &::before { - content: ""; - position: absolute; - top: 0; - bottom: 1px; - right: 0; - left: 0; - border-bottom: 3px solid transparent; - } - } - - &:focus:not(:disabled) { - @include square-style__focus; - box-shadow: none; - } -} diff --git a/packages/edit-post/src/components/text-editor/index.js b/packages/edit-post/src/components/text-editor/index.js index 28293076ef7908..30102330e53776 100644 --- a/packages/edit-post/src/components/text-editor/index.js +++ b/packages/edit-post/src/components/text-editor/index.js @@ -11,17 +11,16 @@ import { withDispatch, withSelect } from '@wordpress/data'; import { __ } from '@wordpress/i18n'; import { displayShortcut } from '@wordpress/keycodes'; import { compose } from '@wordpress/compose'; -import { close } from '@wordpress/icons'; function TextEditor( { onExit, isRichEditingEnabled } ) { return ( <div className="edit-post-text-editor"> { isRichEditingEnabled && ( <div className="edit-post-text-editor__toolbar"> - <h2>{ __( 'Editing Code' ) }</h2> + <h2>{ __( 'Editing code' ) }</h2> <Button + isTertiary onClick={ onExit } - icon={ close } shortcut={ displayShortcut.secondary( 'm' ) } > { __( 'Exit code editor' ) } diff --git a/packages/edit-post/src/components/text-editor/style.scss b/packages/edit-post/src/components/text-editor/style.scss index 9bbb44b8ee96ad..178a253afe5e3e 100644 --- a/packages/edit-post/src/components/text-editor/style.scss +++ b/packages/edit-post/src/components/text-editor/style.scss @@ -5,31 +5,20 @@ flex-grow: 1; // Always show outlines in code editor - .editor-post-title__block { + .wp-block.editor-post-title { + max-width: none; + textarea { - border: $border-width solid $light-gray-500; - margin-bottom: $block-spacing; - padding: $block-padding; + border: $border-width solid $light-gray-secondary; + margin-bottom: -$border-width; + padding: $grid-unit-20; - &:focus, - &:hover { - border: $border-width solid $black; + &:focus { + border: $border-width solid $dark-gray-primary; } } - } - - .editor-post-permalink { - margin-top: -6px; - - // Hide the thick left border in the code editor. - box-shadow: none; - border: none; - outline: $border-width solid $dark-gray-primary; - } - @include break-small() { - .editor-post-title, - .editor-post-title__block { + @include break-small() { padding: 0; } } @@ -41,18 +30,21 @@ // Exit code editor toolbar. .edit-post-text-editor__toolbar { position: absolute; - top: $grid-unit-10; + top: 0; left: 0; right: 0; - height: $block-toolbar-height; - line-height: $block-toolbar-height; - padding: 0 $grid-unit-10 0 $grid-unit-20; + padding: $grid-unit-15; display: flex; + @include break-large() { + padding: $grid-unit-15 $grid-unit-30; + } + h2 { + line-height: $button-size; margin: 0 auto 0 0; font-size: $default-font-size; - color: $dark-gray-500; + color: $dark-gray-primary; } .components-button svg { @@ -61,14 +53,19 @@ } .edit-post-text-editor__body { - max-width: calc(100% - #{$grid-unit-20 * 2}); - margin-left: $grid-unit-20; - margin-right: $grid-unit-20; - padding-top: $grid-unit-50; + width: 100%; + padding: $grid-unit-20 $grid-unit-15 $grid-unit-60 $grid-unit-15; + max-width: $break-wide; + margin-left: auto; + margin-right: auto; + + @include break-large() { + padding: $grid-unit-20 $grid-unit-30 #{ $grid-unit-60 * 2 } $grid-unit-30; + } - @include break-small() { - max-width: $content-width; - margin-left: auto; - margin-right: auto; + // This needs specificity to change the title block appearance on the code editor. + .editor-post-title__input.editor-post-title__input.editor-post-title__input { + font-family: $editor-html-font; + font-size: 2em; } } diff --git a/packages/edit-post/src/components/visual-editor/index.js b/packages/edit-post/src/components/visual-editor/index.js index b34d8a1375b66c..9929a6699674f3 100644 --- a/packages/edit-post/src/components/visual-editor/index.js +++ b/packages/edit-post/src/components/visual-editor/index.js @@ -39,7 +39,9 @@ function VisualEditor() { <WritingFlow> <ObserveTyping> <CopyHandler> - <PostTitle /> + <div className="edit-post-visual-editor__post-title-wrapper"> + <PostTitle /> + </div> <BlockList /> </CopyHandler> </ObserveTyping> diff --git a/packages/edit-post/src/components/visual-editor/style.native.scss b/packages/edit-post/src/components/visual-editor/style.native.scss index 77c87b662c0bbe..223cbacd08bd6b 100644 --- a/packages/edit-post/src/components/visual-editor/style.native.scss +++ b/packages/edit-post/src/components/visual-editor/style.native.scss @@ -5,8 +5,6 @@ border-right-width: $block-selected-border-width; border-radius: 4px; border-style: solid; - margin-left: $block-selected-margin; - margin-right: $block-selected-margin; } .blockHolderFocused { diff --git a/packages/edit-post/src/components/visual-editor/style.scss b/packages/edit-post/src/components/visual-editor/style.scss index b29292d18308af..0093354ef12e00 100644 --- a/packages/edit-post/src/components/visual-editor/style.scss +++ b/packages/edit-post/src/components/visual-editor/style.scss @@ -36,46 +36,27 @@ height: 0; } -// The base width of blocks -.edit-post-visual-editor .block-editor-block-list__block { - margin-left: auto; - margin-right: auto; -} - +// Ideally this wrapper div is not needed but if we waant to match the positionning of blocks +// .block-editor-block-list__layout and block-editor-block-list__block +// We need to have two DOM elements. +.edit-post-visual-editor__post-title-wrapper { + // This padding is needed to match the block root container padding + padding-left: $block-padding; + padding-right: $block-padding; -// The base width of the title should match that of blocks even if it isn't a block. -// @todo: This duplicates CSS from line 49 in block-list/style.scss, and should be -// removed when the Title field becomes an actual block. -.editor-post-title { - // Beyond the mobile breakpoint, compensate for side UI. @include break-small() { - padding-left: $block-padding + $block-side-ui-width + $block-padding + $border-width * 2; - padding-right: $block-padding + $block-side-ui-width + $block-padding + $border-width * 2; + padding-left: $block-side-ui-width; + padding-right: $block-side-ui-width; } -} - -.edit-post-visual-editor .editor-post-title__block { - // Center. - margin-left: auto; - margin-right: auto; - // Apply default block margin below the post title. - // This ensures the first block on the page is in a good position. - // This rule can be retired once the title becomes an actual block. - margin-bottom: ($block-padding * 2) + $block-spacing; // This matches 2em in the vanilla style. + .editor-post-title { + // Center. + margin-left: auto; + margin-right: auto; - // Stack borders. - > div { - margin-left: 0; - margin-right: 0; - } - - // Stretch to mimic outline padding on desktop. - // Note that we can't target the textarea as it can't be stretched. - @include break-small() { - > div { - margin-left: -$block-padding - $block-side-ui-clearance; - margin-right: -$block-padding - $block-side-ui-clearance; - } + // Apply default block margin below the post title. + // This ensures the first block on the page is in a good position. + // This rule can be retired once the title becomes an actual block. + margin-bottom: ($block-padding * 2) + $block-spacing; // This matches 2em in the vanilla style. } } diff --git a/packages/edit-post/src/components/welcome-guide/images.js b/packages/edit-post/src/components/welcome-guide/images.js index e9823943c82b8e..f809e54ce40d7b 100644 --- a/packages/edit-post/src/components/welcome-guide/images.js +++ b/packages/edit-post/src/components/welcome-guide/images.js @@ -6,7 +6,7 @@ import { __ } from '@wordpress/i18n'; export const CanvasImage = ( props ) => ( <img alt="" - src="data:image/svg+xml,%3Csvg width='306' height='286' viewBox='0 0 306 286' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='306' height='286' rx='4' fill='%2366C6E4'/%3E%3Crect x='36' y='30' width='234' height='256' fill='white'/%3E%3Crect x='36' y='80' width='234' height='94' fill='%23E2E4E7'/%3E%3Cpath d='M140.237 121.47L142.109 125H157.255V133H140.237V121.47ZM159.382 119H155.128L157.255 123H154.064L151.937 119H149.809L151.937 123H148.746L146.618 119H144.491L146.618 123H143.428L141.3 119H140.237C139.067 119 138.12 119.9 138.12 121L138.109 133C138.109 134.1 139.067 135 140.237 135H157.255C158.425 135 159.382 134.1 159.382 133V119Z' fill='%23444444'/%3E%3Crect x='57' y='182' width='91.4727' height='59' fill='%23E2E4E7'/%3E%3Crect x='156.982' y='182' width='91.4727' height='59' fill='%23E2E4E7'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M112.309 203H93.1634C92.0998 203 91.0361 204 91.0361 205V219C91.0361 220.1 91.9934 221 93.1634 221H112.309C113.372 221 114.436 220 114.436 219V205C114.436 204 113.372 203 112.309 203ZM112.309 218.92C112.294 218.941 112.269 218.962 112.248 218.979L112.248 218.979C112.239 218.987 112.23 218.994 112.224 219H93.1634V205.08L93.2485 205H112.213C112.235 205.014 112.258 205.038 112.276 205.057C112.284 205.066 112.292 205.074 112.298 205.08V218.92H112.309ZM99.0134 212.5L101.672 215.51L105.395 211L110.182 217H95.2907L99.0134 212.5Z' fill='%2340464D'/%3E%3Cmask id='mask0' mask-type='alpha' maskUnits='userSpaceOnUse' x='91' y='203' width='24' height='18'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M112.309 203H93.1634C92.0998 203 91.0361 204 91.0361 205V219C91.0361 220.1 91.9934 221 93.1634 221H112.309C113.372 221 114.436 220 114.436 219V205C114.436 204 113.372 203 112.309 203ZM112.309 218.92C112.294 218.941 112.269 218.962 112.248 218.979L112.248 218.979C112.239 218.987 112.23 218.994 112.224 219H93.1634V205.08L93.2485 205H112.213C112.235 205.014 112.258 205.038 112.276 205.057C112.284 205.066 112.292 205.074 112.298 205.08V218.92H112.309ZM99.0134 212.5L101.672 215.51L105.395 211L110.182 217H95.2907L99.0134 212.5Z' fill='white'/%3E%3C/mask%3E%3Cg mask='url(%23mask0)'%3E%3Crect x='89.9727' y='200' width='25.5273' height='24' fill='%2340464D'/%3E%3C/g%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M212.291 203H193.145C192.082 203 191.018 204 191.018 205V219C191.018 220.1 191.975 221 193.145 221H212.291C213.354 221 214.418 220 214.418 219V205C214.418 204 213.354 203 212.291 203ZM212.291 218.92C212.276 218.941 212.251 218.962 212.23 218.979L212.23 218.979C212.221 218.987 212.212 218.994 212.206 219H193.145V205.08L193.23 205H212.195C212.217 205.014 212.24 205.038 212.258 205.057C212.266 205.066 212.274 205.074 212.28 205.08V218.92H212.291ZM198.995 212.5L201.654 215.51L205.377 211L210.164 217H195.273L198.995 212.5Z' fill='%2340464D'/%3E%3Cmask id='mask1' mask-type='alpha' maskUnits='userSpaceOnUse' x='191' y='203' width='24' height='18'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M212.291 203H193.145C192.082 203 191.018 204 191.018 205V219C191.018 220.1 191.975 221 193.145 221H212.291C213.354 221 214.418 220 214.418 219V205C214.418 204 213.354 203 212.291 203ZM212.291 218.92C212.276 218.941 212.251 218.962 212.23 218.979L212.23 218.979C212.221 218.987 212.212 218.994 212.206 219H193.145V205.08L193.23 205H212.195C212.217 205.014 212.24 205.038 212.258 205.057C212.266 205.066 212.274 205.074 212.28 205.08V218.92H212.291ZM198.995 212.5L201.654 215.51L205.377 211L210.164 217H195.273L198.995 212.5Z' fill='white'/%3E%3C/mask%3E%3Cg mask='url(%23mask1)'%3E%3Crect x='189.955' y='200' width='25.5273' height='24' fill='%2340464D'/%3E%3C/g%3E%3Crect x='57' y='38' width='191.455' height='34' fill='%23E2E4E7'/%3E%3Cpath d='M155.918 47.8V54.04H149.537V47.8H146.346V63.4H149.537V57.16H155.918V63.4H159.109V47.8' fill='%2340464D'/%3E%3Crect x='58' y='249' width='191' height='37' fill='%23E2E4E7'/%3E%3Cpath d='M160.127 261.4H150.606C149.546 261.4 148.576 261.64 147.696 262.12C146.802 262.612 146.1 263.272 145.59 264.1C145.066 264.928 144.811 265.84 144.811 266.824C144.811 267.808 145.066 268.72 145.59 269.548C146.1 270.376 146.802 271.036 147.696 271.516C148.576 272.008 149.546 272.248 150.606 272.248H151.155V279.4C151.155 279.724 151.282 280.012 151.525 280.252C151.78 280.48 152.086 280.6 152.431 280.6C152.788 280.6 153.082 280.48 153.337 280.252C153.592 280.012 153.72 279.724 153.72 279.4V265C153.72 264.676 153.835 264.388 154.09 264.148C154.345 263.92 154.652 263.8 154.996 263.8C155.341 263.8 155.647 263.92 155.903 264.148C156.145 264.388 156.273 264.676 156.273 265V279.4C156.273 279.724 156.4 280.012 156.656 280.252C156.911 280.48 157.205 280.6 157.562 280.6C157.907 280.6 158.213 280.48 158.468 280.252C158.711 280.012 158.838 279.724 158.838 279.4V263.8H160.127C160.472 263.8 160.766 263.68 161.021 263.44C161.276 263.212 161.404 262.924 161.404 262.6C161.404 262.276 161.276 261.988 161.021 261.748C160.766 261.52 160.472 261.4 160.127 261.4Z' fill='%2340464D'/%3E%3C/svg%3E%0A" + src="data:image/svg+xml,%3Csvg width='306' height='286' viewBox='0 0 306 286' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='306' height='286' rx='4' fill='%231386BF'/%3E%3Cpath d='M45 32C45 30.8954 45.8954 30 47 30H259C260.105 30 261 30.8954 261 32V286H45V32Z' fill='white'/%3E%3Crect x='45' y='80' width='216' height='94' fill='%23DDDDDD'/%3E%3Crect x='144.75' y='118.75' width='16.5' height='16.5' rx='1.53571' stroke='black' stroke-width='1.5'/%3E%3Cpath d='M151 130V124L156 127L151 130Z' fill='black'/%3E%3Crect x='57' y='182' width='91.4727' height='59' fill='%23DDDDDD'/%3E%3Crect x='156.982' y='182' width='91.4727' height='59' fill='%23DDDDDD'/%3E%3Crect x='94.75' y='203.75' width='16.5' height='16.5' rx='1.25' stroke='black' stroke-width='1.5'/%3E%3Cpath d='M95 216L99.5714 212.667L103 214.889L107 211L111 214.889' stroke='black' stroke-width='1.5' stroke-linejoin='round'/%3E%3Crect x='194.75' y='203.75' width='16.5' height='16.5' rx='1.25' stroke='black' stroke-width='1.5'/%3E%3Cpath d='M195 216L199.571 212.667L203 214.889L207 211L211 214.889' stroke='black' stroke-width='1.5' stroke-linejoin='round'/%3E%3Crect x='57' y='38' width='191.455' height='34' fill='%23DDDDDD'/%3E%3Cpath d='M148 49L148 60L153 55.875L158 60L158 49L153 49L148 49Z' fill='black' stroke='black' stroke-width='1.5'/%3E%3Crect x='58' y='249' width='191' height='37' fill='%23DDDDDD'/%3E%3Cline x1='155.917' y1='281' x2='155.917' y2='265.889' stroke='black' stroke-width='1.5'/%3E%3Cline x1='151.472' y1='281' x2='151.472' y2='265.889' stroke='black' stroke-width='1.5'/%3E%3Cline x1='159.333' y1='265.75' x2='150.445' y2='265.75' stroke='black' stroke-width='1.5'/%3E%3Cpath d='M150.139 269.889V273.96C148.211 273.607 146.75 271.919 146.75 269.889C146.75 267.859 148.211 266.171 150.139 265.818V269.889Z' fill='black' stroke='black' stroke-width='1.5'/%3E%3C/svg%3E%0A" { ...props } /> ); @@ -14,7 +14,7 @@ export const CanvasImage = ( props ) => ( export const EditorImage = ( props ) => ( <img alt="" - src="data:image/svg+xml,%3Csvg width='306' height='286' viewBox='0 0 306 286' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='306' height='286' rx='4' fill='%2366C6E4'/%3E%3Crect x='34.5' y='89.9424' width='237' height='113.423' fill='white' stroke='%238D96A0'/%3E%3Crect x='42.2383' y='98.5962' width='219.692' height='95.6618' fill='%23E2E4E7'/%3E%3Crect x='34.5' y='71.6346' width='27.0718' height='18.1324' fill='white' stroke='%238D96A0'/%3E%3Crect x='152.89' y='71.6346' width='18.5282' height='18.1324' fill='white' stroke='%238D96A0'/%3E%3Crect x='61.3516' y='71.6346' width='51.482' height='18.1324' fill='white' stroke='%238D96A0'/%3E%3Crect x='112.613' y='71.6346' width='40.4974' height='18.1324' fill='white' stroke='%238D96A0'/%3E%3Cpath d='M157.577 137.408H149.383C148.471 137.408 147.636 137.628 146.878 138.068C146.109 138.518 145.505 139.122 145.066 139.88C144.615 140.638 144.396 141.473 144.396 142.373C144.396 143.274 144.615 144.109 145.066 144.867C145.505 145.625 146.109 146.229 146.878 146.668C147.636 147.119 148.471 147.339 149.383 147.339H149.855V153.885C149.855 154.182 149.965 154.446 150.173 154.665C150.393 154.874 150.657 154.984 150.953 154.984C151.261 154.984 151.514 154.874 151.733 154.665C151.953 154.446 152.063 154.182 152.063 153.885V140.704C152.063 140.407 152.162 140.144 152.381 139.924C152.601 139.715 152.865 139.605 153.161 139.605C153.458 139.605 153.721 139.715 153.941 139.924C154.15 140.144 154.26 140.407 154.26 140.704V153.885C154.26 154.182 154.37 154.446 154.589 154.665C154.809 154.874 155.062 154.984 155.369 154.984C155.666 154.984 155.929 154.874 156.149 154.665C156.358 154.446 156.468 154.182 156.468 153.885V139.605H157.577C157.874 139.605 158.126 139.496 158.346 139.276C158.566 139.067 158.676 138.803 158.676 138.507C158.676 138.21 158.566 137.947 158.346 137.727C158.126 137.518 157.874 137.408 157.577 137.408Z' fill='%2340464D'/%3E%3Crect x='41.3232' y='77.1135' width='15.8667' height='7.17464' fill='%23E2E4E7'/%3E%3Crect x='66.9536' y='77.1135' width='7.32308' height='7.17464' fill='%23E2E4E7'/%3E%3Crect x='77.9385' y='77.1135' width='7.32308' height='7.17464' fill='%23E2E4E7'/%3E%3Crect x='88.9229' y='77.1135' width='7.32308' height='7.17464' fill='%23E2E4E7'/%3E%3Crect x='99.9077' y='77.1135' width='7.32308' height='7.17464' fill='%23E2E4E7'/%3E%3Crect x='118.215' y='77.1135' width='7.32308' height='7.17464' fill='%23E2E4E7'/%3E%3Crect x='129.2' y='77.1135' width='7.32308' height='7.17464' fill='%23E2E4E7'/%3E%3Crect x='140.185' y='77.1135' width='7.32308' height='7.17464' fill='%23E2E4E7'/%3E%3Crect x='158.492' y='77.1135' width='7.32308' height='7.17464' fill='%23E2E4E7'/%3E%3C/svg%3E%0A" + src="data:image/svg+xml,%3Csvg width='306' height='286' viewBox='0 0 306 286' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='306' height='286' rx='4' fill='%231387BF'/%3E%3Crect x='45' y='99' width='216' height='108' rx='2' fill='white'/%3E%3Cline x1='155.917' y1='161' x2='155.917' y2='145.889' stroke='black' stroke-width='1.5'/%3E%3Cline x1='151.472' y1='161' x2='151.472' y2='145.889' stroke='black' stroke-width='1.5'/%3E%3Cline x1='159.333' y1='145.75' x2='150.445' y2='145.75' stroke='black' stroke-width='1.5'/%3E%3Cpath d='M150.139 149.889V153.96C148.211 153.607 146.75 151.919 146.75 149.889C146.75 147.859 148.211 146.171 150.139 145.818V149.889Z' fill='black' stroke='black' stroke-width='1.5'/%3E%3Crect x='45.5' y='72.5' width='117' height='21' rx='1.5' fill='white' stroke='%231E1E1E'/%3E%3Cline x1='67.5918' y1='72' x2='67.5918' y2='94' stroke='%231E1E1E'/%3E%3Cline x1='141.432' y1='72' x2='141.432' y2='94' stroke='%231E1E1E'/%3E%3Cpath d='M63.4121 93.5417L67.0921 89.875V93.5417H63.4121Z' fill='%231E1E1E'/%3E%3Crect x='52' y='79' width='9' height='8' rx='1' fill='%23333333'/%3E%3Crect x='147' y='82' width='2' height='2' fill='%23333333'/%3E%3Crect x='151' y='82' width='2' height='2' fill='%23333333'/%3E%3Crect x='155' y='82' width='2' height='2' fill='%23333333'/%3E%3C/svg%3E%0A" { ...props } /> ); @@ -22,7 +22,7 @@ export const EditorImage = ( props ) => ( export const BlockLibraryImage = ( props ) => ( <img alt="" - src="data:image/svg+xml,%3Csvg width='306' height='286' viewBox='0 0 306 286' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='306' height='286' rx='4' fill='%2366C6E4'/%3E%3Cmask id='mask0' mask-type='alpha' maskUnits='userSpaceOnUse' x='141' y='25' width='24' height='24'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M152.765 25C146.294 25 141 30.2943 141 36.7651C141 43.2359 146.294 48.5302 152.765 48.5302C159.236 48.5302 164.53 43.2359 164.53 36.7651C164.53 30.2943 159.236 25 152.765 25ZM151.589 32.0591V35.5886H148.059V37.9416H151.589V41.4711H153.942V37.9416H157.471V35.5886H153.942V32.0591H151.589ZM143.353 36.7651C143.353 41.9417 147.588 46.1772 152.765 46.1772C157.942 46.1772 162.177 41.9417 162.177 36.7651C162.177 31.5885 157.942 27.353 152.765 27.353C147.588 27.353 143.353 31.5885 143.353 36.7651Z' fill='white'/%3E%3C/mask%3E%3Cg mask='url(%23mask0)'%3E%3Crect x='141' y='25' width='23.5253' height='23.5253' fill='white'/%3E%3C/g%3E%3Cg filter='url(%23filter0_d)'%3E%3Crect x='48' y='63' width='210' height='190' fill='white'/%3E%3C/g%3E%3Cmask id='mask1' mask-type='alpha' maskUnits='userSpaceOnUse' x='143' y='139' width='20' height='16'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M143.75 141C143.75 140.17 144.42 139.5 145.25 139.5C146.08 139.5 146.75 140.17 146.75 141C146.75 141.83 146.08 142.5 145.25 142.5C144.42 142.5 143.75 141.83 143.75 141ZM143.75 147C143.75 146.17 144.42 145.5 145.25 145.5C146.08 145.5 146.75 146.17 146.75 147C146.75 147.83 146.08 148.5 145.25 148.5C144.42 148.5 143.75 147.83 143.75 147ZM145.25 151.5C144.42 151.5 143.75 152.18 143.75 153C143.75 153.82 144.43 154.5 145.25 154.5C146.07 154.5 146.75 153.82 146.75 153C146.75 152.18 146.08 151.5 145.25 151.5ZM162.25 154H148.25V152H162.25V154ZM148.25 148H162.25V146H148.25V148ZM148.25 142V140H162.25V142H148.25Z' fill='white'/%3E%3C/mask%3E%3Cg mask='url(%23mask1)'%3E%3Crect x='141' y='135' width='24' height='24' fill='%23444444'/%3E%3C/g%3E%3Cmask id='mask2' mask-type='alpha' maskUnits='userSpaceOnUse' x='139' y='54' width='28' height='11'%3E%3Crect x='139' y='54' width='28' height='11' fill='%23C4C4C4'/%3E%3C/mask%3E%3Cg mask='url(%23mask2)'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M139 67L153 54L167 67H139Z' fill='white'/%3E%3C/g%3E%3Crect x='59' y='74' width='188' height='28' rx='3' stroke='%231486B8' stroke-width='2'/%3E%3Cpath d='M211 207.47L212.76 211H227V219H211V207.47ZM229 205H225L227 209H224L222 205H220L222 209H219L217 205H215L217 209H214L212 205H211C209.9 205 209.01 205.9 209.01 207L209 219C209 220.1 209.9 221 211 221H227C228.1 221 229 220.1 229 219V205Z' fill='%23444444'/%3E%3Cpath d='M94.0001 136.4H85.0481C84.0521 136.4 83.1401 136.64 82.3121 137.12C81.4721 137.612 80.8121 138.272 80.3321 139.1C79.8401 139.928 79.6001 140.84 79.6001 141.824C79.6001 142.808 79.8401 143.72 80.3321 144.548C80.8121 145.376 81.4721 146.036 82.3121 146.516C83.1401 147.008 84.0521 147.248 85.0481 147.248H85.5641V154.4C85.5641 154.724 85.6841 155.012 85.9121 155.252C86.1521 155.48 86.4401 155.6 86.7641 155.6C87.1001 155.6 87.3761 155.48 87.6161 155.252C87.8561 155.012 87.9761 154.724 87.9761 154.4V140C87.9761 139.676 88.0841 139.388 88.3241 139.148C88.5641 138.92 88.8521 138.8 89.1761 138.8C89.5001 138.8 89.7881 138.92 90.0281 139.148C90.2561 139.388 90.3761 139.676 90.3761 140V154.4C90.3761 154.724 90.4961 155.012 90.7361 155.252C90.9761 155.48 91.2521 155.6 91.5881 155.6C91.9121 155.6 92.2001 155.48 92.4401 155.252C92.6681 155.012 92.7881 154.724 92.7881 154.4V138.8H94.0001C94.3241 138.8 94.6001 138.68 94.8401 138.44C95.0801 138.212 95.2001 137.924 95.2001 137.6C95.2001 137.276 95.0801 136.988 94.8401 136.748C94.6001 136.52 94.3241 136.4 94.0001 136.4Z' fill='%23444444'/%3E%3Cmask id='mask3' mask-type='alpha' maskUnits='userSpaceOnUse' x='76' y='204' width='22' height='18'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M96 204H78C77 204 76 205 76 206V220C76 221.1 76.9 222 78 222H96C97 222 98 221 98 220V206C98 205 97 204 96 204ZM96 219.92C95.9861 219.941 95.9624 219.962 95.9426 219.979C95.9339 219.987 95.9261 219.994 95.92 220H78V206.08L78.08 206H95.91C95.9309 206.014 95.9518 206.038 95.9694 206.057C95.977 206.066 95.9839 206.074 95.99 206.08V219.92H96ZM83.5 213.5L86 216.51L89.5 212L94 218H80L83.5 213.5Z' fill='white'/%3E%3C/mask%3E%3Cg mask='url(%23mask3)'%3E%3Crect x='75' y='201' width='24' height='24' fill='%23444444'/%3E%3C/g%3E%3Cpath d='M161 205V217H149V205H161ZM161 203H149C147.9 203 147 203.9 147 205V217C147 218.1 147.9 219 149 219H161C162.1 219 163 218.1 163 217V205C163 203.9 162.1 203 161 203ZM152.5 212.67L154.19 214.93L156.67 211.83L160 216H150L152.5 212.67ZM143 207V221C143 222.1 143.9 223 145 223H159V221H145V207H143Z' fill='%23444444'/%3E%3Cmask id='mask4' mask-type='alpha' maskUnits='userSpaceOnUse' x='210' y='140' width='18' height='12'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M215.62 152H210.38L212.38 148H210V140H218V147.24L215.62 152ZM220.38 152H225.62L228 147.24V140H220V148H222.38L220.38 152ZM224.38 150H223.62L225.62 146H222V142H226V146.76L224.38 150ZM214.38 150H213.62L215.62 146H212V142H216V146.76L214.38 150Z' fill='white'/%3E%3C/mask%3E%3Cg mask='url(%23mask4)'%3E%3Crect x='207' y='134' width='24' height='24' fill='%23444444'/%3E%3C/g%3E%3Cdefs%3E%3Cfilter id='filter0_d' x='18' y='36' width='270' height='250' filterUnits='userSpaceOnUse' color-interpolation-filters='sRGB'%3E%3CfeFlood flood-opacity='0' result='BackgroundImageFix'/%3E%3CfeColorMatrix in='SourceAlpha' type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0'/%3E%3CfeOffset dy='3'/%3E%3CfeGaussianBlur stdDeviation='15'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0.0980392 0 0 0 0 0.117647 0 0 0 0 0.137255 0 0 0 0.1 0'/%3E%3CfeBlend mode='normal' in2='BackgroundImageFix' result='effect1_dropShadow'/%3E%3CfeBlend mode='normal' in='SourceGraphic' in2='effect1_dropShadow' result='shape'/%3E%3C/filter%3E%3C/defs%3E%3C/svg%3E%0A" + src="data:image/svg+xml,%3Csvg width='306' height='286' viewBox='0 0 306 286' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='306' height='286' rx='4' fill='%231386BF'/%3E%3Crect x='58' y='44' width='21.3714' height='21.3714' rx='2' fill='%231E1E1E'/%3E%3Cpath d='M68.75 49V60M63 54.25H74' stroke='white' stroke-width='1.5'/%3E%3Crect x='48' y='71' width='210' height='154' rx='2' fill='white'/%3E%3Cpath d='M214 181L214 192L219 187.875L224 192L224 181L219 181L214 181Z' fill='black' stroke='black' stroke-width='1.5'/%3E%3Cpath d='M162 183V194C162 195.105 161.106 196 160.001 196C156.897 196 150.874 196 147 196' stroke='black' stroke-width='1.5'/%3E%3Crect x='144.75' y='178.75' width='13.5' height='13.5' rx='0.875' stroke='black' stroke-width='1.5'/%3E%3Cpath d='M145 189L148.714 187L151.5 188.333L154.75 186L158 188.333' stroke='black' stroke-width='1.5' stroke-linejoin='round'/%3E%3Crect x='79.75' y='178.75' width='16.5' height='16.5' rx='1.25' stroke='black' stroke-width='1.5'/%3E%3Cpath d='M80 191L84.5714 187.667L88 189.889L92 186L96 189.889' stroke='black' stroke-width='1.5' stroke-linejoin='round'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M161 131.5H145V130H161V131.5Z' fill='black'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M161 138.5H153V137H161V138.5Z' fill='black'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M161 146H145V144.5H161V146Z' fill='black'/%3E%3Ccircle cx='147' cy='138' r='2' fill='black'/%3E%3Cpath d='M220 130H226V136H220V130Z' fill='black'/%3E%3Cpath d='M211 130H217V136H211V130Z' fill='black'/%3E%3Cpath d='M226 130C226 133.332 226 136.8 226 139.999C226 143.198 223.5 142.997 222 142.998' stroke='black' stroke-width='1.5'/%3E%3Cpath d='M217 130C217 133.332 217 136.8 217 139.999C217 143.198 214.5 142.997 213 142.998' stroke='black' stroke-width='1.5'/%3E%3Cline x1='90.9165' y1='145' x2='90.9165' y2='129.889' stroke='black' stroke-width='1.5'/%3E%3Cline x1='86.4722' y1='145' x2='86.4722' y2='129.889' stroke='black' stroke-width='1.5'/%3E%3Cline x1='94.3335' y1='129.75' x2='85.4446' y2='129.75' stroke='black' stroke-width='1.5'/%3E%3Cpath d='M85.1389 133.889V137.96C83.2111 137.607 81.75 135.919 81.75 133.889C81.75 131.859 83.2111 130.171 85.1389 129.818V133.889Z' fill='black' stroke='black' stroke-width='1.5'/%3E%3Crect x='58.5' y='81.5' width='189' height='25' rx='3.5' stroke='%23007CA8'/%3E%3C/svg%3E%0A" { ...props } /> ); @@ -30,7 +30,7 @@ export const BlockLibraryImage = ( props ) => ( export const DocumentationImage = ( props ) => ( <img alt="" - src="data:image/svg+xml,%3C%3Fxml version='1.0' encoding='UTF-8'%3F%3E%3Csvg width='306px' height='286px' viewBox='0 0 306 286' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E%3C!-- Generator: Sketch 61.2 (89653) - https://sketch.com --%3E%3Ctitle%3EPage 1%3C/title%3E%3Cdesc%3ECreated with Sketch.%3C/desc%3E%3Cg id='Page-1' stroke='none' stroke-width='1' fill='none' fill-rule='evenodd'%3E%3Cg id='Documentation'%3E%3Crect id='bg' fill='%2361C6E6' x='0' y='0' width='306' height='286' rx='4'%3E%3C/rect%3E%3Crect id='page' fill='%23FFFFFF' x='36' y='30' width='234' height='256'%3E%3C/rect%3E%3Crect id='text' fill='%23E2E4E7' x='124' y='119' width='106' height='13'%3E%3C/rect%3E%3Crect id='heading' fill='%23E2E4E7' x='76' y='96' width='154' height='13'%3E%3C/rect%3E%3Crect id='header' fill='%2340464D' x='36' y='30' width='234' height='41'%3E%3C/rect%3E%3Cimage id='WordPress-logotype-wmark-white' x='45' y='32' width='37' height='37' xlink:href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA+gAAAPoCAYAAABNo9TkAAAABGdBTUEAALGOfPtRkwAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAD6KADAAQAAAABAAAD6AAAAAAYK4+nAABAAElEQVR4AezdB7gkRdX/8UV2yTmDhMuSkQySQUCSpBWUvCACggFFRPQVRREB/6+gooiB8BphEVCygESRIEmyBAlLRiTnzP93oGeZe/eGmek63VXV33qeeubemelTpz49PV013dMzahQFAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQACBUAJThApEHAQQQAABBBAII/DOO++MVqSpijr1CLf2PHuOlddUXy9q6++hbl+fYoop3rSFKAgggAACCCAQhwAT9DjWA1kggAACCGQkoAn2tOrO7KpzFLftf7fua7+dXs9rTbTt9gOqVZS31YhN6FuT+Jf095OqTw1zO+kxTfBf0fMoCCCAAAIIIBBIgAl6IEjCIIAAAgjkL6CJ9wzq5cKqfW238+rv9sm2TcanU21CeVmdnDRh1982uX9MdaLq/a1bTeRf1N8UBBBAAAEEEBhBgAn6CEA8jAACCCDQHIHiyHefemx14ETc/rfJN6V7AZvET5qw6++Jbf9P5Ei8NCgIIIAAAghIgAk6LwMEEEAAgUYJaBJup5Avqbqs6odU2yfic+t/SvUC/1GT7RP42/X/rap3avJup+BTEEAAAQQQaIQAE/RGrGY6iQACCDRTQJPx+dVzm4gvV1T72ybnY1Qp8Qu8oRTvVLXJ+i1FvVWT9of1NwUBBBBAAIHsBJigZ7dK6RACCCDQPAFNxO0ia8uo2kS8fUI+a/M0GtHjZ9TLSRP24u/bNHG3i9xREEAAAQQQSFaACXqyq47EEUAAgWYKaDJuF2BbTXUt1ZVUbVI+VpV9mhAaXN5R3+9TtYn7P1WvVL1Gk3a7kB0FAQQQQACBJAQYzCSxmkgSAQQQaK6AJuTzqfdrqtqEfG3VFVTtd8IpCIwkYL/zfpPqFao2Yb9KE/ZHdUtBAAEEEEAgSgEm6FGuFpJCAAEEmimgybj9/rdduM0m4626cDM16LWTgF2MzibrrXq7Ju32e/AUBBBAAAEEahdggl77KiABBBBAoLkCA05Xtwn5GqozN1eEntcg8JzavFq1NWHntPgaVgJNIoAAAgi8J8AEnVcCAggggEBlAsUR8g+rwU2LuopuOV29sjVAQx0I2Gnx16ueX9TrOMLegRpPQQABBBAIIsAEPQgjQRBAAAEEhhLQpHwuPbax6sdUN1GdXZWCQCoCTynRC1TPU/2rJutPpJI4eSKAAAIIpCfABD29dUbGCCCAQNQCmpBPqQTtKut2lNwm5Sursr8RAiV5AbtS/A2qNlm3I+x2OvxbuqUggAACCCAQRIABUxBGgiCAAALNFtCkfB4JtE5bt6Pl/P54s18STem9/R77X1XfPR1ek/XHm9Jx+okAAggg4CPABN3HlagIIIBA9gKalNtR8nGqNjG3nz5jnyIESmMF7Oi6/aSbTdbP1GT9msZK0HEEEEAAgZ4FGEz1TMeCCCCAQPMENCm309W3V91OdaHmCdBjBDoWeEDPPEX1j5qs22nxFAQQQAABBEYUYII+IhFPQAABBJotoEn58hJoTcoXabYGvUegJ4F7tVRrsn5zTxFYCAEEEECgEQJM0BuxmukkAggg0J2AJuXLaAk7Sm4T88W7W5pnI4DAMAJ367E/qp6iI+u3DfM8HkIAAQQQaKAAE/QGrnS6jAACCAwmoEn5krq/daR86cGew30IIBBU4F+K1jqyfmfQyARDAAEEEEhSgAl6kquNpBFAAIEwApqUL6pIrUn5cmGiEqWkgF1s7A3V11VfK27t75H+11NGTVXUqdv+tvuG+n+MHmMsIIQIyi3KoTVZvyeCfEgBAQQQQKAGAXbKNaDTJAIIIFCngCbl06j9T6jupbpunblk3Pbb6pv9BNdTXdTn9NzXdNqzTc4rK3o92CTdJvAzq87eRbWf0vuAKiW8wOUKeazqn/R6eDV8eCIigAACCMQqwAQ91jVDXggggEBgAU3EllXIz6iOV+V3ynv3fUWLPqg6cUB9QP//V/Vp1Wc0sbIj4dkWvZ5sDGGvo9lU51S1q/r3DagL6v9pVSm9CdiHPH9QPU6vp1t7C8FSCCCAAAIpCTBBT2ltkSsCCCDQpYAmUTNoETuF3Sbmq3W5eFOf/rI6bpPtiUVt/3uiJkr/0f2UDgX0GpxbT+1rq+0Teft7OlXKyAL2u+rHqZ6s1+BLIz+dZyCAAAIIpCjABD3FtUbOCCCAwAgCmhStoqfYpHxH1RlHeHpTH7ZTyu2oZHu9W5OfJ5oKUke/9VqdS+3aLwXYGR7t1U65p0wu8ILumqBqR9Wvn/xh7kEAAQQQSFmACXrKa4/cEUAAgTYBTXRsQmOnr9vEfPm2h5r+p11cza6Q3T4Rv1WTm4eaDhNz//V6XkD5tU/Y7W/7pQG76B3lPYGbdWNH1f+g17N94ERBAAEEEEhcgAl64iuQ9BFAAAFNZNaSgl3wbVvVpn/f1ybdN6m2T8bv0uTlTd1HSVxAr/XR6sISqu0T9xX0v03mm1zsuginqh6r1/qVTYag7wgggEDqAkzQU1+D5I8AAo0UKCYqn1Dnv6pqp7M3sdik2ybjV6napOQqTU4e1i2lYQLaHuZXl9dUtQ+r7NYm7TaZb2Kx096PVLUrwPPBVBNfAfQZAQSSFmCCnvTqI3kEEGiagCYiM6rPe6h+WdUusNWkYle0vlr13cm4bq/VBMQu6EZBoJ+AthO78Nyqqq1J+xr6264436TygDp7lOoJ2k7se+sUBBBAAIEEBJigJ7CSSBEBBBDQhOODUviS6t6qTbl41t3qa2sybrd3aqLxjm4pCHQloO3Hxjv2/fXWEXa7tQvTNaHYd9N/pfpTbT+PNKHD9BEBBBBIWYAJesprj9wRQCB7AU0sllMn7TT2HVTHZN7h+9S/81X/qnqlJhNPZt5fulejgLatOdS8TdQ3Vt1UdaxqzuUNde5k1SO1bd2Sc0fpGwIIIJCyABP0lNceuSOAQLYCmjzYpMEm5htl28lRo+z09L+pnqd6viYN/864r3QtcgFtc4spRZuof0z1I6o5/z77heqfTdTtwzAKAggggEBEAkzQI1oZpIIAAs0W0ARhKgnY75bvr2pXqc6x3KFO2VFyq5drgvBqjp2kT2kLaFucRj1YV9Um7FaXUs2x2K8d/FB1grbF13PsIH1CAAEEUhNggp7aGiNfBBDITkCTgenVqS+o7qs6X2YdfF79uVj13Um5JgEPZtY/utMAAW2jC6qbrcn6R/X3TJl1+1H15yeqx2gbfSmzvtEdBBBAICkBJuhJrS6SRQCBnASKo3SfU5/+R3WujPp2r/pymqqdum4/fWbffaUgkIWAtlu7FsSaqnYq/CdVF1HNpTyhjvw/1V9ou+XsllzWKv1AAIGkBJigJ7W6SBYBBHIQ0ADfTmX/jOqBqrkcMZ+ovpxiVQP7G3RLQaARAtqeV1ZHtytqXyadtiPqh6sep+359Uz6RDcQQACBJASYoCexmkgSAQRyENBAfrT68WnVb6naKbOpFztd/VRVm5Rfm3pnyB+BsgLaxu23122yvq1qLtv4oerLr7WNv6lbCgIIIICAswATdGdgwiOAAAIatE8phZ1Vv6Oa+k85Paw+2Onrf1S9RoN2fpdcEBQE2gW0zdv4ajXV7VXtNPj5VVMu9yn576qeqG3+rZQ7Qu4IIIBA7AJM0GNfQ+SHAALJCmiQ/gElb0fTDlZdQjXVYqe72qTcTmG375QzKU91TZJ35QLFZN2+s27vBTZZT/lrLXcp/4NV7ayZt3VLQQABBBAILMAEPTAo4RBAAIFiQL61JOyI0zKJitjV109SnaB6BYPxRNciaUclUHxot7aSsp9T3Ek11avB36bc7Yyg0/nATgoUBBBAAAEEEEAAgTgFNADfQvWfqqmWK5X4bqrTxSlMVgjkIWDbWLGt2TaXarH3ui3yWCP0AgEEEEAAAQQQQCAbAQ1Sl1e9VDXF8qSS/pHq0tmsEDqCQEICtu0V26BtiymWS5X08gmRkyoCCCCAAAIIIIBAjgIalM6p+ivVt1RTKm8r2YtVd1CdOsd1Q58QSE3AtsVim7Rt07bRlIq9B9p74ZypuZMvAggggAACCCCAQOICGoSOUf2K6rOqKZXHlOzhqoskvgpIH4GsBWwbLbZV22ZTKvaeaO+NY7JeQXQOAQQQQAABBBBAIA4BDTzte+Z3qaZS7MjWuaofVx0dhyJZIIBAJwK2zRbbrm3Dti2nUuw9ku+nd7KSeQ4CCCCAAAIIIIBA9wIabNr3RC9IZXSsPJ9W/b7qAt33liUQQCA2AduWi23atu1Uir1ncn2L2F5M5IMAAggggAACCKQqoMHlbKo/VX1DNYVyn5L8kuoMqZqTNwIIDC1g23axjdu2nkKx9057D51t6F7xCAIIIIAAAggggAACwwhoMGmnlu6j+pRqCuUaJbmd6pTDdIuHEEAgEwHb1ott3rb9FIq9l9p7Kl+1yeQ1SDcQQAABBBBAAIFKBDSA3Fj1dtXYi13p+UzVdSqBoREEEIhSwN4DiveCFK7+bu+tG0cJSVIIIIAAAggggAAC8Qho0DiX6gTV2MsrSvCXqovHo0cmCCBQt4C9JxTvDfYeEXux99q56jajfQQQQAABBBBAAIEIBTRQ3FU19tPZn1COB6vyW8MRvoZICYFYBOw9onivsPeMmIu95+4aixt5IIAAAggggAACCNQsoMHhwqoXxjyCVW4TVT+rOk3NXDSPAAIJCeg9Y9rivcPeQ2Iuf1VyCydES6oIIIAAAggggAACIQU0GLQLLH1F9SXVWMvDSuzzqlOF7DuxEECgWQL2HlK8l9h7SqzF3ovtPZkLXTbr5UlvEUAAAQQQQKDpAhoALq96nWqs5XEl9mVVjpg3/cVK/xEIKGDvKcV7i73HxFrsvXn5gN0mFAIIIIAAAggggECMAhr02eD0cNVYf9P8v8rta6rTxehHTgggkIeAvccU7zX2nhNjsfdoe6/mQ8o8XnL0AgEEEEAAAQQQ6C+ggd5HVO9WjbE8o6S+pTpj/6z5DwEEEPATsPec4r3H3oNiLPae/RE/ASIjgAACcQlMEVc6ZIMAAgiEF9DgbmZFPUJ1T9XY3vdeUE5Hqf5wiimmeE63lAYI6DVp37GdTXUO1VlVZ2ir9iHNwP/tKOLoEeo7evz1EeprAx5/Vf8/o/q06lPFrf39tF6PFovSEIHifXJ/dffLqrF9UGiv7eNVD+B9UgoUBBDIWiC2gWrW2HQOAQSqF9Cgc5xa/YXqvNW3PmyLL+nRn6keoQGnTYwoiQvotWb7VPv5u/lVFyiqve7sPpuIt9/apPwDqjGXF5Xcu5N13bZP3u3vR1QfKOqDeg0/r78pGQjodTy7unGA6j6q00fWpceUz+f0ejszsrxIBwEEEAgmwAQ9GCWBEEAgJgENMu073D9W3SumvJTLm6r2gcGhGmQ+EVlupDOCgF5XNuFerKiL6NYm4q0Jud1OrdrE8qw6/aDqpEn7gL8f1+vdjoJSEhHQa30upfot1c+p2tkbMZVjlcx+ek29HFNS5IIAAgiEEGCCHkKRGAggEJWABpYrK6ETVZeIKrFRoy5QPjaovCOyvEinTUCvn5n074dUF1dtTcZbt3bqOaV7ATtd/t+qtw+o92h7sA+tKJEKaHtYSqnZh52bRJbiXcpnZ71+bogsL9JBAAEESgkwQS/Fx8IIIBCTgAaSdsqwnZr5PdUxEeV2t3L5igaS50aUU+NT0evFjgraJHxZ1eWKW/u7T5VSjYBN3G2iNXDifq+2l7eqSYFWOhHQ9rK5nvcjVdtmYilvKJGDVO2rQm/HkhR5IIAAAmUEmKCX0WNZBBCIRkCDRzu9+Peq60WT1KhRdtrvIao/0+DRBpKUmgT0+rAPbGwSvmpRV9CtHRls6inp6nrUxS5ed6eqHR29RvUfqrczCZNCjaXYjuy76d9WnaXGVAY2fZnu2EWvj4cHPsD/CCCAQGoCTNBTW2PkiwACkwlo0Lit7vyVql14K4ZiR/6OUz1IA8YnY0ioSTno9WD7tkVVW5Nxu7UJOb+nLISEi1207jpVm6xbvUbb1390S6lYQNuYXfTQzlT6jOqUFTc/VHP2awR76zVx6lBP4H4EEEAgBQEm6CmsJXJEAIFBBTRItO8DH62626BPqOfOS9Ssfc/8lnqab16reh3Yqeorqa6rar+XvJZqLB/WKBWKo8BExW4dYbdJ+43a9l5zbI/QbQLa9uysFPt++gZtd9f952+UwBf1OrAPdCgIIIBAcgJM0JNbZSSMAAImoIHharo5UXUR+z+Ccq9ysN/oPT2CXLJOQeveTku3o+I2IbdqE/LpVSkI2OT8StWLVC9U/ae2ybd1S3EU0Da5tcIfoRrT+7FdQM4+vKEggAACSQkwQU9qdZEsAghoIGinUx6o+m1VO3Jad3lBCRymepQGgxy5c1gbWue2r7IjdXYVaatrqnK6uhAoIwrYac+XqNpk/SJto/ZBGsVBoPjg7MsK/U3VGR2a6Dak/TqAXQPkcK13+9oRBQEEEEhCgAl6EquJJBFAwAQ0AOzTzR9U7YhpDOUMJfEFDf4ejSGZnHLQup5T/dlI1SbkG6vOo0pBoKzARAV4d7Ku24u17T5VNiDL9xfQtjuf7jlG9eP9H6ntPzujYrzW9cTaMqBhBBBAoAsBJuhdYPFUBBCoT0CDvk3V+kmqMXy3+HHlYd9xPK0+kbxa1vq1/dEqquNUbV3bd8rZRwmB4ibwjiLfqPoX1dO1Pf/TraUGBtY2/Ul1264REsOHa3YmxU5ax+c3cFXQZQQQSEyAwU9iK4x0EWiaQDFx+5b6fbDqByLo/wnK4asa6D0bQS5Jp6B1O5U6sJ6qHWmzibkdeaMgUJfAA2r49KJeoW2c766XXBPaxmdRiCNV9ygZKsTitj4PVj1U69Y+nKEggAACUQowQY9ytZAUAgiYgAZ3M+vm96pb2v81l3vU/l4a2F1acx5JN691OpM68DFVm5Rvpmr/UxCITeAJJXSW6p9V7VT412NLMKV8tN2vr3yPVV00grzPVg72m+nPRZALKSCAAAKTCTBBn4yEOxBAIAYBDeiWVR42OK57QGcXGvqh6sEa0L2qW0qXAlqXdoX1rVR3ULXT1+3IOQWBVASeV6LnqtrR9fP0PsDPd/Ww5vQ+MI0WO1h1f9XRqnUW+8B1G63LW+tMgrYRQACBwQSYoA+mwn0IIFCrgAZyOyqB41WnqzWRUaNuUPt7ahB3U815JNe81qFNwu1IuU3KbXJe97pUChQESgvYh3Tnq/5O9Vy9N3BkvUtSvTesoEXs/X3lLhcN/fSXFdDe3yeEDkw8BBBAoIwAE/QyeiyLAAJBBTRws6Mq9lu6Xw4auPtgNnD7juqPNXjj53k69NP6s5/A20DVJuXbqM6iSkEgV4Gn1LGTVX+r94nrcu2kR7+K94r9FPu7qnV/eHeUcjhA69DOlqIggAACtQswQa99FZAAAgiYgAZsc+vmVNV17P8ay0Vqe28N1u6rMYekmta6s68hfFr1U6ofTCp5kkUgjMAdCvNb1T/oveORMCHzj6L3jrHq5a9UN6y5t39X+9tq3f2n5jxoHgEEEOAnbHgNIIBA/QIapK2pLGxyPl+N2dhR8/00QLMLGVFGENA6m15P2VZ1d9W6P1QZIVseRqAyAbtS+MWqNlm3n26z9xXKCAJ6P9lLT/mxap1H0x9V+zZJv2qEdHkYAQQQcBXgCLorL8ERQGAkAQ3MvqDn2MBszEjPdXzcvmtuv5F7t2MbWYTW+lpLHbFJ+XaqM2TRKTqBgI/ACwp7mur/6b3lCp8m8omq95Yl1JsTVev8bvobat8+qD0mH1l6ggACqQkwQU9tjZEvApkIaDBmV/S1o9W71NglO9p1hOpBGpDZwIwyiECxrnbSQ/uqLjfIU7gLAQSGF7hZD/9M9US917wy/FOb+6jea+yD2u+pHqD6gRolfqe27atOdlFACgIIIFCpABP0SrlpDAEETECDsDl1c6bqGvZ/TeVhtWu/hXtZTe1H36zW07xK8vOqe6vaOqMggEA5gWe0+AmqP9d7z/3lQuW7tN571lPvfq86f429vFptj9N6+m+NOdA0Agg0UIAJegNXOl1GoE4BDbwWV/t/UV2kxjxOVdt2dMQGy5QBAlpHq+guO1q+vWqdXz0YkBn/IpCNgJ29c66qHVW/UO9F72TTs0Ad0fvQrAplF5DbNlDIXsLcq4U20/rh60+96LEMAgj0JMAEvSc2FkIAgV4ENOBaR8udoTpbL8sHWOZFxfiiBlu/CRArqxBaN1OqQ/bTaDYxt++ZUxBAoBqBu9TMMaq/0XuTfW+d0iag96bd9O/RqnVd8+Jptf1xrZu/65aCAAIIuAswQXcnpgEEEDABDbJ21M2vVae2/2so16jNnTXIsiMilEJA68WOUu2puo/qgsXd3CCAQPUCNjm37z7/RO9T/66++Xhb1PuUnXFlF5BbraYsX1O7n9Z6mVBT+zSLAAINEqjzAhwNYqarCDRbQIOrAyVgg6s6Judvqd3vqa7N5FwKRdE6WVL15/r3IdUfqDI5L2y4QaAmgRnVrv2qxR3aNieoLltTHtE1W7x3r63E7L3c3tOrLrbvOlHrxPZlFAQQQMBVgCPorrwER6DZAhrMjJbAL1X3qEniAbU7XoO7K2pqP7pmtU42VlL7qW6iyj4gujVEQghMErDvpZ+terjew+wMIIoE9B5mE/U/qC5UE8gJavezWidv1tQ+zSKAQOYCDM4yX8F0D4G6BDSImklt228Ab1RTDuerXTul3b4/2Pii9bGhEOzo0+qNxwAAgfQELlbKh+n97NL0Ug+fsd7P7Ks5J6luGj56RxEv1LM+qfXxfEfP5kkIIIBAFwKc4t4FFk9FAIHOBDR4WkDPtKPWdUzO7ajToaqbMzl/92jTuloff5OHDSiZnAuBgkCCAh9VzpdoW75KdYsE8w+ast7b7Rc4Nle193p7z6+62L7timJfV3XbtIcAApkLcAQ98xVM9xCoWkADlhXVpv180LxVt632nlO13za300IbXbQebDJuR8ztyDkFAQTyErhZ3Tlc9TS939lPtjW26L1uS3X+96oz14DwmNq0D4NvrKFtmkQAgUwFmKBnumLpFgJ1CGigZEc0Tlat4+dwblO7W2ugdE8dfY+lTa2DlZXLIaqbxZITeSCAgJuA/UTbN/W+9ye3FhIIrPe9RZXm6arL1JCu/XznDloH9sE0BQEEECgtwCnupQkJgAACJqAB0h66OVO1jsn5BLW7epMn5/JfTtUGqNerMjkXAgWBBggsoT6epm3/GtX1GtDfQbtYvPfbWUO2L6i62D7vTPnvXnXDtIcAAnkKMEHPc73SKwQqFdDA5Etq8DjVKStteNQou4rufhqc7aT6UsVtR9Gc7JdS/aOSuUn141EkRRIIIFC1wKpq8FK9F5ynunzVjcfQnu0DbF+gXPZTrfoK67bvO172ti+kIIAAAqUEOMW9FB8LI4CABiTfkIJ9F7Lq8h81uJ0GZJdX3XAM7cndTun8jqoNSPmwNYaVQg4IxCFgF02zK5wfpPfH++NIqdos9P64rlo8RXXualt+t7UD5f79GtqlSQQQyESACXomK5JuIFCHgAZBh6ndA2to+2q1aT9x82gNbdfapMzt4nt25eJdVUfXmgyNI4BAzAKvK7lfqh6q98r/xpyoR256r5xPcU9TXcMj/ggx7bfrvznCc3gYAQQQGFSACfqgLNyJAALDCWjgY+8dR6nWcTrfz9XulzX4eWO4HHN7TOZj1Kd9Vb+tOmNu/aM/CCDgJvCCIh+p+iO9b9oFzRpTivdN21d9voZO/1Rt2r6qjp+Bq6G7NIkAAqEEmKCHkiQOAg0R0IDHTqc+VtUuCldlse8Ufk6DneOrbDSGtmRuv7lrg70lY8iHHBBAIEkB+1rQ11V/17RJo95D91S/f6Fa9VlHJ6jNveTd6J/CkwEFAQS6EGCC3gUWT0Wg6QIa5Njg5neqO1Zs8bzas1PaL6y43Vqbk/dCSuBHqtvUmgiNI4BATgJXqTNf0PupXViyMaX4oNNOeZ+p4k7bleV3lXfVF66ruJs0hwACoQSYoIeSJA4CmQtocDO1umhXCx9XcVcfUnuba3Bza8Xt1tacrKdR419T/R/VaWtLhIYRQCBXgbfUMft+ul1I7plcOzmwX3pvXVb32e+VLzDwMef/7SdIt5f1a87tEB4BBDIQYIKewUqkCwh4C2hQM53aOEPVTrWustyoxmxy/liVjdbZlqztA5Afqy5cZx60jQACjRCwi8d9Q/X/9D7biO9K6z12XvXXJukrqlZZ7Aywj8v55SobpS0EEEhPgAl6euuMjBGoVECDGTsd8BzVdSpt+L0BlB1xaMTvm8t5Cfn+RHWTip1pDgEEELhGBHba+w1NoND77fTqp50RtnnF/f272ttCzva1LQoCCCAwqAC/nTsoC3cigIAJaBAzm24uUq16cm5Xah/XhMm5jGdQ/V/1107hZ3IuBAoCCFQusJpavFbvRb8s3vcrT6DKBot9i52tZPuaKovtSy9qgnGVqLSFQG4CHEHPbY3SHwQCCRQDiEsVbrlAITsJY1e6PUCDJ7swWvZFxjupk0eo2u/1UhBAAIEYBJ5SEnba+/F6L87+tHe9D39FfbX34SoPWt2i9taX79O6pSCAAAL9BJig9+PgHwQQMAENWOy0djty/mH7v6LyitoZrwHLnytqr7Zm5Nunxv9Pdf3akqBhBBBAYHiBS/TwnnpPvn/4p6X/qN6Tt1Ev/qBa5UU5r1N7G8r3+fQF6QECCIQUqPLTwpB5EwsBBJwENFCxC8LZd86rnJw/ofbWb8jkfC/11U5nZ3IuBAoCCEQrsIEyu1X7hH1Usz6gU+x77D3Z9kVVFdvHnlPsc6tqk3YQQCABgazfcBPwJ0UEohLQQGFqJXS2apVXa79T7W2mAVLWR2lkO7/6ebwq3zMXAgUBBJISuFzZ7qH36XuSyrrLZPU+PVaLnKu6ZJeLlnm6Xd19S9nyE2xlFFkWgYwEOIKe0cqkKwiUEdDAZLSWt6vaVjk5v17trdWAyfmu6icXgRMCBQEEkhRYV1nfov3EfqrZjh21L7pP/VxL1fZNVRXb5/6x2AdX1SbtIIBAxAIcQY945ZAaAlUJFAMu+/7djlW1qXauULXfOM/2+3dynVt9/JWqXS2YggACCOQgcJU6sbveu+/KoTOD9UHv3XYdFjuSvvZgjzvdN0Fx7TosbzvFJywCCCQikO2noIn4kyYCtQtoIGIf1B2rWuXk3E7p2yTzyfl26uPtqkzOhUBBAIFsBNZUT27SvuMA1Smz6VVbR4p9k30dyfZVVRXbBx9b7JOrapN2EEAgQgGOoEe4UkgJgSoFNBj4idr7UoVtnqW2ttMA6LUK26ysKXnOrsaOUd2+skZpCAEEEKhH4Fo1+ym9n9u1RLIrej+367KcorpVhZ37qTz3rbA9mkIAgcgEOIIe2QohHQSqFNDg4zC1V+Xk/GS194mMJ+c2iLOj5kzOhUBBAIHsBVZVD6/XvmT3HHta7Ks+ob7Zvquq8qVi31xVe7SDAAKRCTBBj2yFkA4CVQloAPANtXVgVe2pnRNUd9aA580K26ykKVnOrPobNXamqn3vnIIAAgg0RWB6dfQEvQeebO+FuXW62GftbH2ssG8HytL20RQEEGigAKe4N3Cl02UEtOO3o+Z2antV5adq6Msa6LxTVYNVtSPLDdXWr1Xnr6pN2kEAAQQiFbCfy9xJ7/X/iDS/ntPSe72NmY9SrfKss31laftPCgIINEiAI+gNWtl0FQET0CDDTkW0QUZV5XANMGyQkdXkXI4fUP22EC9QZXJe1auJdhBAIGaBhZXc3/Xe+A17j4w50W5zs32Y7cu03OHdLlvi+UfJ0fbZFAQQaJAAR9AbtLLpKgLa0W8uBTsNu6or7x6oAc33c5OXo10Izn6WbtPc+kZ/EEAAgUAClyiO/WzYY4HiRRNG+wA7/byqifpbamucHO1n3ygIINAAASboDVjJdBEBE9CAYkXdXK46g/3vXOxouZ3Snt2peXK0iyKdqrqgsyHhEUAAgdQFnlQHdstxcql9gZ3qbmejVTGWflHtrCvHG3VLQQCBzAWyOv0o83VF9xDoWUADiQW0sH36XtXkfO9MJ+efl+HfVZmcC4GCAAIIjCAwhx4/R/sgO1V7qhGem9TDxT5ubyVdxde3bN9tjrYvpyCAQOYCVXzqlzkh3UMgbgHt0GdShleoLltRptld1EaGdpXiY1V3qsiQZhBAAIHcBK5Th7bRxPbhnDqm/UOVF129VXZry/D5nAzpCwII9BfgCHp/D/5DICsBDRxGq0OnqVY1ObfvnGd1WrsMl5TftapMzoVAQQABBHoU+LCWu0Hvqev0uHyUixX7vAMrSs725acV+/aKmqQZBBCoWoAJetXitIdAtQK/VHMbVdSkXa09qwvCaRC0vezsqM/SFRnSDAIIIJCzwFzq3MV6b90np04W+76qLhpn+3Tbt1MQQCBTASboma5YuoWABkD2if4eFUn8VAOUb1bUlnszshujar8Tf7JqFd/bd+8TDSCAAAKRCIxRHkfrPfbXqtNEklPpNIp9YFVnkO0hu6qO2pe2IQACCHQnwHfQu/Pi2QgkIaAd945K9ETVKrbxE9TOZzQ4qeJCOe7+srPfND9FdQ33xmgAAQQQaLbA9er+1tp/ZPG9dO0/bJ97nGoVH47bPndn2U3QLQUBBDISqGLwnhEXXUEgfgENEOz7fReqTl1BtnaE2QYIb1fQlnsTsrNTB09StSsPUxBAAAEE/AWeUBPbaj9yuX9T/i1oP2Jnp9oH5Dv4tzbqNbWxkezs10UoCCCQiQCnuGeyIukGAiaggcHiujlDtYrJ+VlqZ5eMJudfUH/OU2VyLgQKAgggUJFA63vpX6yoPddmin3iLmrE9pHexfb1ZxT7fu+2iI8AAhUJcAS9ImiaQcBbQDtom1j+Q3UR77YU347Qb6mBiH16n3SRm70PHqG6f9IdIXkEEEAgfYHfqguf1b7l1dS7on2LTZ7PVrUzs7zLvWpgdbk96d0Q8RFAwF+ACbq/MS0g4C6ggYBdaOcS1Sq+N22/qb6JBgIvu3fMuYHC7fdq5pPOTREeAQQQQKAzgSv1tHHaxzzV2dPjfZb2MdMpuwtU164gy6vVxgY5fLhRgRVNIBC1AKe4R716SA6BjgWO1TOrmJzbBX02z2RybmccXKzK5FwIFAQQQCASgbWUx1Wa3I6NJJ+e0yj2lZsrgO07vYuNAWwsQEEAgcQFmKAnvgJJHwENYuy70/Z9N+9ypxqwI+fPezfkHV9mi6oNO9qwpndbxEcAAQQQ6FrArqdytd6rV+16ycgWKPaZmyot24d6l12KMYF3O8RHAAFHAU5xd8QlNALeAtoR2wTzMtUxzm3ZVXbt+233O7fjHr4wO1MN2RF0CgIIIIBAvAL2Vaodte+p4oJrrgra9yysBuw6MXZRPM/yhoKvJ7OrPBshNgII+AlwBN3PlsgIuApoZz+PGjhV1Xty/ora2CqTybmdzm6ntTM5FwIFAQQQiFzAvsN9uvZ3dqZY0qXYh26lTtg+1bPYmODUYozg2Q6xEUDASYAJuhMsYRHwFNCOd7Tin6I6n2c7im2/bz5eA4trnNtxDy8zu0q7mdkF9SgIIIAAAmkI2Fj1Z3oPP0I16TM/i33pePXH9q2excYGpxRjBc92iI0AAg4CTNAdUAmJQAUCR6qNdSpo5wANKP5cQTtuTWiAMqXqMWrAzJIe3LkhERgBBBCIX+CrSvFkvZ/bz5clW4p96gEVdMDGCLbfoyCAQGICDFYTW2Gki4AGJztK4aQKJH6ugUTSpxXKano5nay6RQVeNIEAAggg4CPwksLamNVOebef+rSfYXtat8mW4oPjz1fQgZ1kNaGCdmgCAQQCCTBBDwRJGASqENAOfVm1YxeZsUGKZzlXwW0A9JZnI56xZWXf0T9HdWXPdoiNAAIIIFBK4Dkt/S/V29tuH9Hf9oshL9it9kXvnhKu93X7fvUsqm/ovmd1m2xRX6ZU8nbB0s2dO2EX2rOLvN7q3A7hEUAgkAAT9ECQhEHAW0A785nVxvWq9hNhnuWfCr6uduZ2xCLJIqsFlPilqosk2QGSRgABBPIVeF1ds6Pg51tt8sRR+yo7y+ty1ZVUPcs9Cr6KrO3DEAoCCEQuwAQ98hVEegiYgHbitq3az8x4n6r9kNpYTTvxx3SbZJFVnxK3ybndUhBAAAEE6hewI+A2IT9e9a8pfwAcmlL7rHkV0y7Eah8sexY7o8x+keUdz0aIjQAC5QW4SFx5QyIgUIXAQWrEe3JupxNunvjkfKz68DfVPlUKAggggEC9Ao+q+UNVF9a+xfYvp6sme3aWB6U87ANxO83d9sGexcYQ3/JsgNgIIBBGwI7KURBAIGIBfbr+MaVnn3x7fqD2puJvpoHChRFTDJuanOzUfztyPv+wT+RBBBBAAAFvAZuYH6J6gvYrtn+hjCCgfdhGespfVEeP8NQyD9uZDFtonZxXJgjLIoCArwATdF9foiNQSkA77D4FsO+Ez1oq0MgL76kd9gkjPy3OZ8hpCWV2iar378LHCUBWCCCAQBwCzyiN/6d6tPYpr8SRUjpZaF+2p7I9zjljW0craf1MdG6H8Agg0KOA5xG5HlNiMQQQMAHtqO0Kr39Q9Z6cH5P45HwpGV2myuRcCBQEEECgJgGbWI7V/uQHTM57WwNyO15LHtPb0h0vZWOKPxRjjI4X4okIIFCdABP06qxpCYFuBb6pBdbqdqEun3+1nr9fl8tE83QNMJZRMpep2k+qURBAAAEEqhewi4tuqsnlXqpJ//RZ9XSDtmj7ZNs3exYbW9gYg4IAAhEKcIp7hCuFlBDQxHM1KVyh6vldtP8ovp3mZt8VTK7IaDklfbHqHMklT8IIIIBAHgK/Vjf2037kuTy6E0cvtH+zM8Ls621zO2Zk1wZYW+vOriBPQQCBiAQ4gh7RyiAVBExAO+YZdHOiqufk3HbM2yU8OV9R+dt3zpmcC4GCAAIIVCzwhtrbW/uQ3Zmch5cv9s3bKbLnBfZsjHFiMeYI3wkiIoBAzwJM0HumY0EE3AR+psiLuEV/L/ABGgBc7tyGS3gNJlZRYDtyPrtLAwRFAAEEEBhO4Ck9uJH2IccO9yQeKydQ7KMPKBdlxKVtrGFjDgoCCEQkwCnuEa0MUkFAk89tpXCKs8QE7fh3cm7DJbx87NT/C1RndmmAoAgggAACwwncoQft98zvH+5JPBZOQPu9kxRtx3ARB41kZ9SdOugj3IkAApULMEGvnJwGERhcQDvhBfTIzaqzDv6MIPfepiira0f8UpBoFQaRz5pq7jzVmSpslqYQQAABBN4TuF03G2j/8QQg1Qlo3ze9WvuHql0U1avYT68tr3VrF/yjIIBAzQKc4l7zCqB5BExAO2DbFn+n6jk5f07xt050cr6scv+LKpNzIVAQQACBigX+pfaYnFeMbs0V++yt9aftw72KjT1+V4xFvNogLgIIdCjABL1DKJ6GgLPA1xR/Pcc23lHsXbSjv8exDZfQGjAspMDnq3Jau4swQRFAAIFhBey0dibnwxL5Pljsu3dRK7Yv9yrrKbCNRSgIIFCzAKe417wCaB4BTUBXloL95ukYR43vaQf/bcf4LqFlYxeCs5+bW9KlAYIigAACCAwnYD/HuYr2Hw8P9yQeq0ZA+8RD1NJBjq3Z1fnX0Pq+wbENQiOAwAgCTNBHAOJhBDwFtLOdTvFvVF3csR07+mwX9XnbsY3goQsbu1r76sGDExABBBBAYCSB1/WE9bTvsA+QKREIaL9oZ76eq7qpYzp3K/aKWu8vO7ZBaAQQGEaAU9yHweEhBCoQOEpteE7OH1D8nRKcnNvvs9rV7JmcC4GCAAII1CBgv3PO5LwG+KGaLPbl9isstm/3KjYm+bFXcOIigMDIAkzQRzbiGQi4COiT8HEK/BmX4O8FfUs347VDf8axDa/Qxynw5l7BiYsAAgggMKzAT7Xv+M2wz+DBWgSKffp4NW77eK+yVzFG8YpPXAQQGEaACfowODyEgJeAdnyzKPYvvOIXcQ/Xjty+v51Ukc3hSni3pJImWQQQQCAfAbso3Nfz6U5+PSn27bav9Cy/KMYqnm0QGwEEBhFggj4ICnchUIHAEWpjXsd2rlHsQxzju4TWYOCLCvwNl+AERQABBBAYScCOyn5KE8BXR3oij9cuYPt429d7FRuj2FiFggACFQtwkbiKwWkOAU1C15PCJape29+Lir2CBlj36jaZIpftlOwEVT44TGatkSgCCGQmcJj2Hd/KrE/Zdkf7zUXUuZtUZ3DqpP2sm/3E3mVO8QmLAAKDCHhNEAZpirsQQEA702mkcIvqYo4an9bO9DeO8YOHlssGCnqe6lTBgxMQAQQQQKATATu13T7ctau3UxIR0P5zN6X6a8d0/63Yy+l1wVkVjsiERqBdgCNV7Rr8jYC/wHfUhOfk/NQEJ+cryOR0VSbn/q8/WkAAAQSGEvgak/OhaOK9v9jnn+qYoY1ZbOxCQQCBigQ4gl4RNM0goE+5l5fC9ar2E2Ie5WEFtU+5k7lqu0wWVs5Xqc7jAUJMBBBAAIGOBC7TvmP9jp7Jk6IT0L50ViVlZ+fN75Tcm4q7il4jNzvFJywCCLQJcAS9DYM/EfAS0M5zSsU+XtVrcv62Yu+S2OTcrmR/viqTcyFQEEAAgZoE7HvGB9TUNs0GECj2/bsolI0FPIqNXY4vxjIe8YmJAAJtAkzQ2zD4EwFHgS8r9iqO8Y/QDvoyx/hBQ2snb+89J6kuHjQwwRBAAAEEuhWwr0bZ2V2UhAWKMYDnVddtDGNjGQoCCDgLcIq7MzDhEdBk1E7jvk11OieNGxR3De2c33CKHzysTA5T0AODByYgAggggEC3Aqtp/3Fttwvx/PgEtG8do6yuVl3ZKbuXFXcZvV7ud4pPWAQQkABH0HkZIOAvcKya8Jqc285y58Qm59soZ37r3P91RwsIIIDASAJXMzkfiSidx4uxwM7K2MYGHsXGMjamoSCAgKMAE3RHXEIjoE+zPyWFDR0l9tMO+S7H+EFDy2NpBfytKmfvBJUlGAIIINCTwFE9LcVC0QoUY4L9HBPcsBjbODZBaASaLcAgudnrn947CmgHNpfC2+/KzubUzEXaEW/kFDt4WHnMrKDXqdpPtlAQQAABBOoVeEjNj9V+xK7QTclMQPvcC9UlrwMETyv2UnrtPJEZG91BIAoBjqBHsRpIIlOBn6hfXpNzO31t71TcNFCwDwNPVGVynspKI08EEMhdYAKT86xXsY0RvE51t7GNjXEoCCDgIMAE3QGVkAhoQrqxFHZwlPi2Blb3OcYPHfq7Crh56KDEQwABBBDoWeDUnpdkwegFijHCtx0T3aEY6zg2QWgEminAKe7NXO/02lFAOyz7vdCbVe371h7FrtpuV919yyN46JjyGKeYp6vyfhMal3gIIIBAbwL3ax8ytrdFWSoVAe1/p1Su16h6XdX9X4q9vF5LfE0ilRcFeSYhwBH0JFYTSSYm8Fnl6zU5t53gnglNzpdUvr9XZXIuBAoCCCAQiQBHzyNZEZ5pFGOFPdWG1wTaxjo25qEgV0YWRQAAQABJREFUgEBAASboATEJhYA+rbbvZdnp3F7lSO1wb/IKHjKuLGZSvDNUZwwZl1gIIIAAAqUFziodgQBJCBRjhiMdk/1uMfZxbILQCDRLgAl6s9Y3vfUXsMm514Xh7lFsz8l/MB3trO2IuR05XyJYUAIhgAACCIQQeFVBrg8RiBjJCNjYwcYQHsXGPAd7BCYmAk0VYILe1DVPv4MLaFLqfarXXvok3AZWKRS7MM1WKSRKjggggEDDBK7TvuS1hvW50d0txg6fcUT4XDEGcmyC0Ag0R4AJenPWNT31F/ixmrALxHmU47WDvdQjcOiY2knb1dq/Ezou8RBAAAEEgghcESQKQZIS0BjiMiV8vFPSNvaxMRAFAQQCCNhpqBQEECgpoEnpFgpxdskwQy3+uB5YSjvXZ4d6Qiz3y2Fu5XKr6pyx5EQeCCCAAAL9BDbX/uQv/e7hn0YIaB89izp6h+o8Th3eUq+tc5xiExaBxghwBL0xq5qOeglohzdGsX/oFV9x90lhcl70//90y+Tc8cVAaAQQQKCkwG0ll2fxRAWKscQ+jun/sBgTOTZBaATyF2CCnv86pof+Al9UE4s7NXOGdqh/coodNKx2yp9XwM2CBiUYAggggEBIAfvu+cMhAxIrLYFiTGG/sOJRbCxkYyIKAgiUEOAU9xJ4LIqAJqV2tPjfqjM7aLygmEtqZ/qoQ+ygIeVgV2u/UXXaoIEJhgACCCAQUuAO7VPsgqaUBgtonz2fun+n6owODM8p5mJ6nf3XITYhEWiEAEfQG7Ga6aSjwKGK7TE5t5QPS2Rybqf4n6jK5NzWGgUBBBCIV8Drp7bi7TGZTSZQjC0Om+yBMHfYmMjGRhQEEOhRgAl6j3AshoA+gV5eCns6SdynuEc5xQ4d1n5fdeXQQYmHAAIIIBBc4P7gEQmYqoCNMWys4VH2LMZIHrGJiUD2AkzQs1/FdNBRwHZuXtvQV/UJd/S/U6sd8Noy+LqjMaERQAABBMIJPB8uFJFSFijGGPs79cHGRqkcZHAiICwCvQt4TS56z4glEUhAQBPTLZXmek6pXqId5+lOsYOFlcFMCvZ7Vd5HgqkSCAEEEHAVeNE1OsGTEtBY4wwlfIlT0usVYyWn8IRFIF8BBtb5rlt65iSgHY5dXNFO6/Yobynofh6BHWL+TDH7HOISEgEEEEDAR4AJuo9rylFtzGFjD4/y3WLM5BGbmAhkK8AEPdtVS8ccBbZR7BWd4h+nT7RvcYodLKx2uNsq2C7BAhIIAQQQQKAKASboVSgn1EYx5jjOKWUbK9mYiYIAAl0I2JFACgIIdCigial9qGUT6A91uEg3T3tWT7afJnmym4Wqfq4MPqg2b1Wdteq2M2nvdfXj6UHqU7pvYH1H99nV8c16ddWPqNrFCXMpt6kjdnrlP1Tt9f+yqm1js7fV2Yq/7bZVzcP+nlqV0iwB2yaeVx24DQ3cduz/F1SnUbVtyH6feV3V9VTt6zlNLTtpHzOhqZ2n34MLaL8+hx6xn4ydZfBnlLr3di29nF53b5eKwsIINEhgdIP6SlcRCCGwvYJ4TM4tt0MSmJzbh3q/VW3y5NwmCDbwtwml1efa/rb/nyn+b7+1yYT9/4zW8Uu67aW8O6jWQMom6gepbtZLkEiWuVh5fEcWV5bJRxY28bKJur0e26sNMq3afa2/7Xbm4n+7tcpZZEKoodgFMNu3m/a/bTt5VrX91v62atvRs3rd9Ho67g/1mplRMT6v+lVVm5Q0rfBzmE1b4x3018Ye2jYO0VN/1MHTu32KjZls7MQHQ93K8fzGCnAEvbGrno53K6Cd15Ra5l+qdiQmdLlbAZfRTvKN0IFDxpPBfornsQMPmeZgsd7UnS8W1SbIA/+2CbcdlRt4a/fZ5MFq6+8XtJ5qPxKgdbGHcjpGNaWjyLYe9pPfz3Rba5Gf7f9mUJ1ZdabitvW3/W/VJnPtf9vz2+v0bf/n/IG3fSj1iurA7cb+t+3JtpuB207r/4Hbz3Na/7X/QoXW/3zK+RTVtVSbVPaRv71vUBDoJ6BtYozuuE3Va4yztF57vX641i9X/kEgd4GcBxS5rzv6V73AeDXpseOynnxFO67YJ+c2obFB+v+o2qTQTh2126kGqfbe0qr2wYZVW96qHbW0Ab9Ncq22/rYdt03gzKFV7X87JfxVVWvbbjv5u98kPIYJgfIOWtSnEzSgukdB/6pq6yD2YutyS+V9fgyJKo/WmRA2kSxdtC5sW2hN3lsT9+l0nx2xHHjb2nbab1vbkQ2S26ttO7bNtFfbjlrbT/s21L79tP9tE+Juth/7qsHAbci8sila/49qna2vDp2lumk2HRu5IxxBH9mokc/QNvGGtomvqPPnOADY2Gm86m8dYhMSAQQQQKCJAtppjVa9V9WjRDFhaeJ6zaHPekHu5vGidIj5xRy86UNeAnqdz6h6m8PrPdaQB+e1BulNaAG9cM93evHaGIoDg6FXGPGyFLBP5CkIIDCywKf1lLEjP63rZ9hRLjttnIJATwI66vEbLWhH0WMulyvPo2NOkNyaKaDXpZ1B8dkG9X7eBvWVrvYmYGMSG5uELjaGsrEUBQEERhBggj4CEA8joE987dTTg5wkfqEB4h1OsQnbHIEDIu9q7PlFzkd6ngJ6D75C8c/0bCOi2B+MKBdSiVCgGJP8wim1bxVjKqfwhEUgDwEm6HmsR3rhK7CXwi/g0IR9x/NQh7iEbJiABlS3qMvXRdrtG5TftZHmRloItAROaP2R+S0T9MxXcKDu2djExiihy4IKaGMqCgIIDCPABH0YHB5CQJ/02kWcDnSSOFoTlyecYhO2eQKnRtrlUyLNi7QQaBe4QP8EuWBge9AI/54/wpxIKTKBYmzi9bWkA4uxVWS9Jh0E4hFggh7PuiCTOAU+r7Q8vrNnA8Ej4+wyWSUq8M9I874q0rxIC4FJApqQ2K9F2E9M5V7m0ORojtw7Sf+CCByhKPbzoqGLjalsbEVBAIEhBJigDwHD3QhoEGM/lfR1J4kfa0D4lFNswjZT4M5Iu801FiJdMaQ1mUCs29BkiZa8Y5mSy7N4AwQ0Rnla3TzKqatfL8ZYTuEJi0DaAkzQ015/ZO8r8AWFn8uhiWcV80cOcQnZbIFXYuw+H0TFuFbIaQiBV4e4P7e7l82tQ/THTcDGKjZmCV1sbGVjLAoCCAwiwAR9EBTuQkCf7NqV2/d1kjhSk5bnnGITtrkCUza36/QcgSACTRkTMUEP8nLJP0gxVvH6Ot6+xVgrf0h6iECXAk3ZGXXJwtMRGLWTDOZzcHhSMX/qEJeQCCwUI4EGYLPGmBc5ITCIQJTb0CB5lr1r9bIBWL5RAj9Rb23sErrYGMvGWhQEEBggwAR9AAj/IlAIfMVJ4gf6RLoJVwp24iPsMALLDfNYnQ/xfdc69Wm7G4FYt6Fu+tDJc5fhg7NOmHiOCWjM8qJufuCk4TXWckqXsAhUI8AEvRpnWklIQAOXTZSuxymA/1HcYxKiINW0BDaPNN21Is2LtBCYJKD3/RX1j8dZU5PaiOiPKZQL22VEKySBVGzsYmOY0GXZYswVOi7xEEhagAl60quP5J0EvuoU9/v6JPplp9iEbbCABjizqftbREowPtK8SAuBdoFd2/9pwN/rNqCPdDGQQDF2+X6gcAPDeI25BrbD/wgkI2CfolIQQKAQ0ERnef15kwPII4q5qHZyTblKsAMhIYcS0OvWfgrH66KGQzXbzf0b6bV/UTcL8FwEqhLQ9rOg2rKfA5yuqjYjaOcObZNLR5AHKSQioO1kGqV6j+oHHVJeQa/Hmx3iEhKBJAU4gp7kaiNpR4H9nWIfxuTcSbbhYTVoWkkE+0TOcLTytF9GoCAQo8DRSqpJk3NbB0tpm2SCHuOrMdKcijHMYU7peY29nNIlLAK+AkzQfX2JnpCABiv2qfAODik/oJgnOMQlZMMF9JrtE8HZqrH/xNqSyvFXypeztgRBiUdAr8kfKJut4smo0kw+WWlrNJaDgI1lbEwTuuxQjMFCxyUeAkkKMEFPcrWRtJOAnSI8xiG2fff8dYe4hGywgAYzK6v7F6umcmGr3ZTrz5W3xzam0BQEOhfQ63Aq1R9riQM6Xyq7ZzJBz26V+naoGMt4fBfd9gtf8s2e6AikI8DRjHTWFZk6CmigNqPCP6Q6c+Bm/qt4C3J6e2DVBofTa3Umdd8GMt9WTXGya98z3F3bxD91S0GgcgFtQ3YFczut3a7c3vSypLbFu5qOQP87F9D2Y99Ff1B1zs6X6uiZz+lZC+j1+EJHz+ZJCGQswBH0jFcuXetKYE89O/Tk3BI4hsl5V+uBJw8ioAHRHKqbqdqk4mHV76mmODm33i2veoP6cpXqZ1TtN5mntgcoCHgI6PU1peoKqp9TvU5tXKHK5Pw9bI6ie7zoSsa012zJEG6LF2Maj5+MtTGYjcUoCDRegCPojX8JAKAd4Wgp2JVJFwqs8YrF1M7MjqJTEBhUQK8/uzjVvG3VroXQqvPrb3td2lWmcy5vqXN2RGZicWtns9gHEa36iP5+StvSO7qlIDBJQNuPHWiwI3mtbci+8tG+/dg2tKhq0y4Cpy53VG7SdsWHFR1RVfckva4XUWtTad3YrwtEV5SfbXP2XfRpAydnMe0Xb94MHJdwCCQlwAQ9qdVFsh4C2tHYheEmOMT+lXYyn3WIS8iIBYoJg/0uuQ1grM5R3M6l27kH1Hn0v52yThlZwK7j8KjqYwPqf/R/qz5hf2u7sw/HKIkKaBuyyXRr+2nfhgZuP63/oz3amMgqWEzbjH1ITYlEQNuATXx/rfXiceHaIL1Ujr9UoL2DBOsfZEf1++T+d/EfAs0SYILerPVNbwcR0E7met1tF9wKWexIn3237+6QQYlVvYBeH3Yq+UdVZ1G1U/Da66z63ybjrTq7/rbn8d4qhBrLS2r7yQH1af3/zID6LyYmEnEu2oaWVRN2RNC2nfbtyP62bci2m9Y2ZLf2HVdKdQL/q+3gf6prjpY6EdB287iet6HWzW2dPL/q5yi/xdXmnaqh93c3qM+rVN0f2kMgJoHQG1VMfSMXBEYU0A5mbT3p7yM+sfsnnKkdzMe7X4wlYhPQa8TeJ+0UazuFlpKXwNXaTtfMq0vx9Ubb0AHK6gfxZUZGhYB9eGUX53oZkXgEtN3YwYMHtF4+EU9W/TNRjmfonnH97w3y3zrq9xVBIhEEgQQFuEhcgiuNlIMK7BU02vvBfvj+n/yVsoAGCXY2xO9S7gO5DymwhgaYCw/5KA+EEjgtVCDiuAjYWQvjXSITtIyAXZdja71HrVAmiPOyXmMdr7GZMwfhEQgjwAQ9jCNREhTQTs9Or/S4gu21mtR5HJVPUDmblE/Jpid0ZKDAbgPv4P+wAno/vF8Rrw0blWiBBfYNHI9w5QUeUAg7g+u75UP5RCjGOh7b9ieLMZpP4kRFIHIBJuiRryDScxWwIwahr0BqCR/pmjXB6xC4UY3aYImSn8DO+XUpyh7xIVeUq2VSUktrQrThpP/4IwaBh4okttK6ifk72R5jHhub8d4cw6uQHGoRYIJeCzuNRiKwp0MedqTozw5xCVmjQHGa+0k1pkDTfgKLaPBr16Kg+Apwmruvb4joHEUPoRguxhNtoQ5p+zu2P23MY2Of0OUzoQMSD4FUBJigp7KmyDOogAbkH1bA5YMGfS/YUZrM2W86U/IT4Ahgfuu01aNdWn9w6yOg90U7A+UfPtGJGkhgc+0b7TfjKXEItE/QP6Z1s3ocafXPohjzHNX/3iD/LV+M1YIEIwgCKQkwQU9pbZFrSAGPT2afUYInhEySWPEIaBByk7J5MJ6MyCSggH3fceqA8Qg1uAAfcg3uEsu99n3nL8WSDHmM+u8Ag5iPotvYx8ZAoYvHWC10jsRDILgAE/TgpASMXUAD8RmU4w4Oef5Skzj7/WVKvgK/z7drje6ZXcV6y0YLVNN5O83dfhWBEq/AntpH8pOScayfgRP0jbRu1okjtf5ZFGOfX/W/N8h/OxRjtiDBCIJAKgJM0FNZU+QZUsAm5zOGDKhYb6v+PHBMwsUnwBHA+NZJqIw4zT2U5BBxNIi3i15dPcTD3B2HgF2c65txpNL4LAZO0A0k5qPoNgaysVDIYmM1jwMqIXMkFgLBBZigByclYAICHqdMna/B58MJ9J0USwhoHd+ixR8sEYJF4xXYVEdq7Eg6xVfgj77hiR5A4DPaFhYKEIcQJQS0v3lNiz8/IMR6WjfrD7gvin+LD+DOd0jGY8zmkCYhEQgnwAQ9nCWREhDQjm05pbmqQ6rHOcQkZJwCv40zLbIqKTCVlt+pZAwWH1ngT3oKp7mP7FTnM2xbOKjOBGh7ksCTk/56/4+Yj6J7jIVW1dht2fe7z18I5C/ABD3/dUwP+wt4fBL7uJo4p38z/JexAKe557tyd823a3H0TEfZHlEmV8SRDVkMI/ApTYoWG+ZxHqpGYOARdGt1ba2bjappvutWbCxkY6LQxWPsFjpH4iEQTIAJejBKAsUuoB3aNMpxZ4c8f61B55sOcQkZoYDW9W1Ka2KEqZFSeYEP632Cn5kq7zhSBD7kGkmo/sdHK4WD60+j8Rm8MITA14a4v9a7i7HQrx2SGF+M4RxCExKB+ASYoMe3TsjIT+CTCj1r4PB2qqb9vAilWQKc5p7v+t4t365F0zM7zT30xaSi6VxGidgVtD+UUX9S7MpQE/QNI143NiYK/TUWG7vZGI6CQCMEmKA3YjXTyULA4xSpS/SJ8b0IN07AJhiUPAXG59mteHql98zHlM3f48mITIYQsDHi94Z4jLurERhqgm6tR/mb9cWY6FIHHo8xnEOahESgvAAT9PKGREhAQJ80L6Y013VI9XiHmISMXEADkFuV4u2Rp0l6vQkspPeLj/S2KEt1IcBp7l1g1fjUrbU9eOw7a+xSUk2/OEy2u2jdxPrLEx4Xi1tX/bWxHAWB7AWYoGe/iulgIbC9g8RTinm6Q1xCpiHABCON9dRLlrv0shDLdCXwZz2b09y7IqvtyUdpYsR4sR7+4Y6g22/Wx3pU2cZGNkYKXTzGcqFzJB4CpQV4wy1NSIBEBLZzyPN3OpJqv1MaVdFAahrVvaNKKs9kTsuzW/RKAp+w7QgJPwG9d9qVnv/m1wKRAwqsqFi7B4xHqM4FhpugW5Qv6L3KLugXVSnGRr9zSMpjLOeQJiERKCfABL2cH0snIKCd11JKc1mHVGM9vd0+Yd7Xob+EbBPQAORf+tdOdafkJzCLujQuv25F1yPOQolulQyZ0GHal8405KM84CUw0kGABdTw1l6Nl4zrMUZathjTlUyNxRGIW4AJetzrh+zCCHicEnVlMUELk2HYKF9QuKW0E1s1bFiiDSLABGMQlEzu2jWTfsTcDTvN/a2YEyS3SQJz6a+DJv3HH1UJvNlBQ1F+IF+Mka7sIP9un8JR9G7FeH5yAkzQk1tlJNyDgMebuccnwz10rf8impSvons+XNzL92j783j8d7ZHUGJGIbCRtqc5osgk0yQ0gH9CXbss0+7l2K0vaZtYNMeORdynTiboaxX7/hi74TFW8jjoEqMdOTVYgAl6g1d+E7qunZad2m6nuIcszylYrEdO7eh5q2yv/kf33bRWcjncaoJxs/phlZKfwBh1aef8uhVdj2J9L40OKoKEplIOP4ogjyal0MkE3TyiPIquvGz7tjFTyGJnCHp8bTFkjsRCoJQAE/RSfCycgIDH0fMJmpi9HFvftcOyn1tp/2R5Tv2/WWx5ZpgPE4wMV2rRJU5z91+3dpp7p5MQ/2xoYSSBLbWv2WikJ/F4MIFOt43ttF7mCdZqoEDFWGlCoHDtYTzGdu3x+RuBWgWYoNfKT+MVCHi8iZ9UQd69NLG7FrKfXWkvnOberuHz91k+YYkagcBKGvQuGUEe2aagAfyT6tyl2XYwz44dre3CjqZT/AU6naDb+vicfzo9teAxZvIY2/XUORZCwEOACbqHKjGjENAAYgUlsnjgZB5VPI+LnpRKU32dQgE+O0iQLfTYzIPcz12BBDTBuE2hbgwUjjDxCXwqvpSyy4izUNJapUso3QPSSjnZbN/oIvPPan8/dRfPr+qpNmaysVPIsngxxgsZk1gIRCPABD2aVUEiDgLtp3uHCn+aJmRvhwoWMM4mirXIIPHst5w9HAZpqtF3McHId/XvVHwAlm8P6+/Z6Uqh0yOF9WdLBibwTW0XfVC4C7zTRQtz6bk7dPH8Sp5ajJlOc2iMsY0DKiHjEGCCHsd6IAsfAY9ToGKdiLVfHG6gJt+jHSgS/n9Ocw9vGkvEBZXI+rEkk2MeGsA/pX5dlGPfMu6TfZ3q6Iz7F0vXpuoykZgvFtdlV0Z8uscYb8RGeQICVQgwQa9CmTYqF9An+/ZzY2MDN/yw4l0VOGbpcMVRjM2GCbSmnhPaYpjmmveQJhj/Uq9vaF7PG9NjPuTyX9Wxfvjp3/N0W7CvUI1LN/0kMu92gr6i1slaEfbMxk42hgpZxqqvNtajIJCdABP07FYpHSoEPE59OlUTsW5ON6tqZdh3z4fblu376Vwszn9tMMHwN66rha01EBx4Aca6csm13TPUsW6+b5urQ2r9+om2jelSSzqhfLudoFvX9oitf8XY6VSHvDzGeg5pEhKB7gSGG9R3F4lnIxCXwLYO6UQ3AdPAyC4I08nOmN9zdnhBDAjJae4DQDL6dyb1ZeuM+hNdVzSAf0ZJXRhdYiQ0ksBCesJBIz2Jx3sW6GWCvq3GBtP33KLfgh5jKI+xnp8AkRHoUIAJeodQPC0dAe2YVle2NmgIWR5UsGtCBgwUy04vnKODWIvJZc0OnsdTehTQBONOLXpdj4uzWPwCnObuv448BvD+WdPC/tq/LAWDi0AvE/QZlEmME1cbQ9lYKmRZqBjzhYxJLARqF2CCXvsqIAEHga0cYp4S6ent47voK6e5d4HV41OZYPQIl8BiH9VAcO4E8kw5xTOV/Ospd6ChuY9Rv3/R0L57d7uXCbrltLt3Yt3GL8ZQHvtIjzFft93j+QgEFWCCHpSTYJEIbOqQh8dOpVSamizMrgDd9HU7LdPrzr5Urg1amNPc813Zo9U1viriuH41gH9W4f/q2ASh/QQ+ov3Lp/zCNzZyr/vsdbQ+Fo1QzWMs1c04KEISUkJgcgEm6JObcE/CAtohzaP0Vwjchfs1cIzx1GX7iRE7ctFpmU1P3KLTJ/O87gX0OrlbS8X4VYjuO8MSgwlwmvtgKmHv8xjAh82QaEMJHKF9sO1nKOEE7DozvZbdel3Qa7liLHV/4PgrFGO/wGEJh0B9AkzQ67OnZR8B+yTVrloesnhceTREfr0czeM09xDyw8dggjG8T8qPLq+B4IdS7kACudtZKK8lkCcpTi4wp+7638nv5p4SAr0eQbcmP6X3qxjH+aHHVDbm4yh6iRcZi8YnEOOGG58SGaUk8DGHZP/oELNUSO10+xSgl4u+baZl7dR4ip/A6X6hiRyBwG4R5JBtCjrC9pw6d0G2Hcy/Y3toH7NW/t2srIdlJujzK8uPVpZp5w15jKmYoHfuzzMTEGCCnsBKIsXOBDQomFLP3KizZ3f8rHs1YPxnx8+u7ol29LyXMwVsZ8/vhjquJ71e7PS9qx2bIHS9AjvovYZ9p+864CwUX1/P6LZf+qW2EbtmA6W8gF2RvUzZsczCHssWY6p7A8feuBgDBg5LOATqEWCQUY87rfoIrKawswYOfVrgeKHC9XJ6e6ttvkfbkvC7ZYLhZ1t35FiPStXtErJ9TnMPqVl9rGXU5FeqbzbLFsue8ba1Jq5ljsJ7oYYeW9nYz8aAFASyEGCCnsVqpBOFgMfp7X+JTVc72xWV01Il8lpNMWK8umuJLkW3qE0wKPkK8CGX47rVEbYXFP48xyYI7S/wHe1nFvJvJvsWZivZw1m0vMfYqGRaozzGVjH2s6wTyzdUgAl6Q1d8pt0O/R2k5+V0VYRW3fz2+VDpM8EYSibA/Zpg3KcwVwYIRYg4Beyo1HRxppZNVpyFkvaqtO3jJ2l3IYrsyx5Bt07sEEVP+idhYysbY4UsoceAIXMjFgJdCTBB74qLJ8cqoMHyXMpt5cD5XayJ1puBY5YKp37aNhtiZ1vmFPlSfWjQwkww8l3Z06trn8i3e1H07Gxl8WoUmZBErwLjtM9ar9eFWe5dgRAT9C1j+0CxGFtdHHgdr1yMBQOHJRwC1QswQa/enBZ9BDZR2F4umjZcNucP92BNj22gducL0PZY7cjWCRCHEEMLcJr70DY5PMJZKI5rUQP4FxX+XMcmCF2NwA+1rwm9b64m85pbkds0SiHEmTr2geKWNXdnsOZDj7HsdWZjQQoCyQswQU9+FdKBQsDj1KbQO48QKyvkkW8mGCHWyBAxNMGYqIf+PsTD3J2+wPoaQM+bfjei7gFnoUS9ejpKbiU9a5eOnsmTBgrMNvCOEv9HdzV39cVjjOUxFizBzqII9CbABL03N5aKSECDZHsdh/7U9A5NsB6MqJuj1M+plc82AXPatogZMCShBggwwRgAktG/9rOOTDx8V6gdQX/ZtwmiVyBwmPY101bQTm5NhDi9vWWyqdbBTK1/Yrgtxlh3BM5lE/WTuU1gVMJVL8CLuHpzWgwv8GGFDLkjswxjvILw+sor5A52ZsUbZ52luAnY92gp+QqEPKMlX6Uee6YB/EtalNPce/SLaDH7acL9I8onlVRCjmvsA/7NIux46LGWmdmYkIJA0gJM0JNefSRfCHic0uRx6lXZFbZF2QCDLM8RwEFQQt2lCcYDivW3UPGIE53Acjpas0J0WeWVEGeh5LE+v65tZe48ulJZL0JO0C3pGD+Q9xhreYwJK1vpNISACTBB53WQg0Do3760UyovjxDG4yIvdjrYnBH2NaeUmGDktDYn7wvXcpjcJOQ99nvJdiSdkrbADEr/kLS7UHn2Ib+Dbslvpv39VJX3YvgGbawV+mssoceEw/eARxFwEGCC7oBKyOoEtLOZTq2tHLjFy3Tk87XAMUuFUz+XU4AFSwUZfOExujvGi8cMnm2a956VZtpk3aHADto+7fvoFAcBvRfb4P0ch9CErF5gd20ri1bfbLItzhM4c/uK3HqBY5YKV4y1LisVZPKF7efWbGxIQSBZASboya46Ei8EVtPt6MAaHqdclU3R4+h5KydOc29JONxqAPKwwl7qEJqQcQjYldw3iiOVbLPgLJQ8Vq3tqw/OoyuV9KLPoZWPO8QsGzL0mMteZzY2pCCQrAAT9GRXHYkXAms5SITeWYRI0eP75628VtGnzUu0/uHWRYAJhgtrNEE5zd13VdiFpOx30SnpC+yo/c2H0u9GJT1YyKGVreRvvxceU/EYc3mMDWMyI5fMBZigZ76CG9C90G/C9+mI579jctPOdC7ls6pzTp9yjt/08GcL4J2mI2Tc/3HaTu07thQHAb0nv6Kwtg1R0hewcech6Xejkh70ObTyQcUM/bXAUmkWY677SgWZfOHQY8PJW+AeBBwFmKA74hLaV0ADYnv9rhG4FY9PcsumuLkCeG+r4yP8VL2sWzTLawDyiJK5JJqESCS0gH3fcdvQQYnXT4CzUPpxJP3PNtrfRDVJjE2zGN8s4JRXE05zX6MwdCIkLAK+At6Dft/sid50gWUEYL/lHbJcEDJYoFiep7e3UrSBwHqtf7h1EWCC4cIaTVCu5eC7KuzD0xd8myB6hQKHVthWik3Np6S9rrge41XOQ4+9bGzIVylSfOWT87sCTNB5IaQs4HEK05UxgegTYNtBb1xRTnyP1hfarkTNae6+xnVG/4i21/nrTCDntnUWyqvqH7+IkM9K3lTby9r5dCd4Tzy+f95KckXZx/bzqh5jL48xYsuQWwRcBZigu/IS3Fkg9JvvXRoEPuWcc7fh19cCVX239RPaaU/bbYI8vzMBvbYe1TMv6uzZPCtBAdufchTdd8VxFoqvb9XRv1t1gwm11+eYq10kLqpfnijGXncF7jMfAAUGJVx1AkzQq7OmpfACoSfoHp/glu11Fae3t3KcUX/E+N20Vn453DLByGEtDt2HnYd+iEcCCNhpsM8HiEOIOAQ20IfCq8SRSnRZ9DlntIlz/F7Chx6DhR4j9tInlkGgJwEm6D2xsVDdAtqp2/ez+gLncVXgeCHCef7++WD5cZr7YCrh7rPT3N8OF45IkQl8SO9NXPzKaaXoKNtrCn2mU3jC1iPwtXqajb7VPucMq/rqXDfdCD0G6yvGit3kwHMRiEKACXoUq4EkehDw+GQ09M6hh269v4h2LEvpP8/vob3f2Pt/baR2537/X/4KKaAJxuOKd2HImMSKToAPuXxXCWeh+PpWHd2u6D626kYTaM973z+P3JeLzMFjDOYxVoyMjXRyFGCCnuNabUafQr/pPi22OyOj+0gN+UypNneuod0mNckEI++1vb0GvqPz7mKtvfurWn+21gxoPKSA7XP2Dxkwk1gLV9CP2E5ztzGYjcVCltBjxZC5EQuBIQWYoA9JwwORC4R+071aRzffiazP69aUDxe68oXnNHdf37qj2xkom9adRK7t6336dfXtjFz719B+fVofas3R0L5P1m1ZTKM7GzdBL8ZgV08GUu6O0GPFctmwNAIdCjBB7xCKp8UjoJ3XdMpmhcAZeZxaVTbFOo6gW84ryHjZssmz/OACGoQ8oUdC/+br4I1xb10CfMjlK89ZKL6+VUe3Xw/5YtWNRtze0srNzizwLmtpXz+1dyNdxg89FrPxjI0ZKQgkJcAEPanVRbKFwGq6DX0Kaeirh5ZaWdqhLKIAdiG8ugoTDF95Jhi+vnVH31Lb8Ex1J5Fx+/Zzhc9k3L8mdu0LTKQmrfaqPiC3I/WrTmo1jj9Cj8VsrGhjRgoCSQkwQU9qdZFsIRD6lKU3Ffe6yHTrOnreYthZgyXeH1oa4W/PVcg3woclYiQCdkRwu0hyyS4NnYVi287p2XWs2R2aXd3fvdkEk3q/zKS//P+o66t0Q/XMxmI2JgtZQo8ZQ+ZGLAQGFWAAPigLd0YuEPpnjG7UgO/lyPpc907Tjt5/NDKTbNLR6+2/6oxd7IqSrwBnofiuW85C8fWtI/pn62g0wjarOoJuXa/7YEA//mIsdmO/O8v/E3rMWD4jIiAwggAT9BGAeDhKgdA7r9DfeQqBVvcE3frABCPEmhw6BhOMoW1yeGQdnYWyYA4dibQPFyuv0Fd8jrSrjUnrQ9pmVm9Mb4fuaOgxztAtjRq1hsxDf2VwuPY6eSz0mKxKz076x3MQGFGACfqIRDwhJgHtSKZXPmMD5xR6Z1AqPfVxAQWo4gquI+W5deE90vN4vDcBO839rd4WZakEBKZQjrsmkGeSKepIm50G++ckkyfp4QT2GO7B3B/TPnc29bHK68/MoPZWisw19JhsLGOZyNYw6YwowAR9RCKeEJmAfRJqA9+QJfRFScrmFsPRc+uD7bi3KdsZlh9cQBOMp/TIXwZ/lHszEdg5k37E2g3OQol1zfSe1w6aTNm+p6mljqO9sYw5Wus89JjMxox1uLb6wy0CXQswQe+ajAVqFgj9JvuQJkqP1Nyngc3HtLPkCODAtRP2fyYYYT1ji7akJhtcQdhvrVyq0E/6hSdyDQI2OW/yBRZDj3E6WYUxjTlGFWOyhzpJvIvn1OHaRXo8FYH+AkzQ+3vwX/wCywVO8abA8UKEi+miLRtoglHl6XYh/FKKcZaSDX3F2pT634RcuZaD01rmNHcn2PrD7ll/CrVlUMdEcm3t50OfmVgWMPSF4kKPHcv2j+URGFaACfqwPDwYoUDoN9lbY+qjdpJzK58lIsrJ3iPGR5RPVqlogvG8OmTfRafkK7C9tusx+Xav9p5xFkrtqyB4AnbhsqWDR00jYB0T9FlFs1hkPKHHZqHHjpFxkU5uAkzQc1uj+fcn9M4r9E6g7BqI6lSzojMcASy7VodfngnG8D6pPzqHOrBZ6p2IOP/LlJv9bCElL4HGXSyuOIq9TE2rcdWa2h2q2dBjs9Bjx6Hy5n4EgggwQQ/CSJAqBLTzml/t2Ce9IUvonUDZ3NYqG8Bh+WVkv4JDXEK+J3CObl4DI2sBPuRyWr06C8V+CeFPTuEJW5/ArtrvNO3MEztrYMaayHOfoM9ajCFr4qVZBLoTYILenRfPrlcg9ClKr6s7d9XbpclaX3Gye+K4g4vFOa2H4jR3rubu5BtJ2C00OJwlklxyTIOzUPJbq3bmyXr5dWvYHq057KO+D37YN3zX0e/WEjZGC1lCjyFD5kYsBPoJMEHvx8E/kQuEPkXpzuIiQzF1e/mYkmnLxX76Zsq2//kzrAATjLCesUWbWgltH1tSGeXzN/XlPxn1h668JzCuYRB1TtBXiOmMhWJsdmfg9R96DBk4PcIh8L4AE/T3LfgrfoHQn35GdXq7do5jtQpmjnQ1zKu8No40txzSOk+dCH20IAeXnPrAae5Oa1OD+bcV+jSn8IStT4AJenX206ip2CawocdooceQ1a0dWmqcABP0xq3ypDsc+s019Jt/WdzYv+fNBKPsGh5ieU0wntNDZw/xMHfnIbCmPoRbOI+uRNkLzkKJcrWUSmp+bTMrl4qQyMLqp53Sv3jN6eb+PfTQY8iaVxfN5yzABD3ntZtR37TzmkrdCf3zY0zQu3uNjNN6qOsCNt1lmuazmWCkud46zdp+Z5hrOXSq1f3zrtAij3e/GEtELtCUo+hrRLAecp+gL1GMJSOgJgUEhhdggj68D4/GI7CkUgl9RVcm6N2t3+n09E92twjP7kLgfD2Xq7l3AZbgU8cnmHMSKRenuZ+aRLIk2Y1AUybodX7/vLU+Vmr9Eclt6DGajSFtLElBIHoBJujRryISLARCn5r0nAZ0D0WmG+sV3NuZOALYrhHwb70en1e4swKGJFR8AovqCE4MA/H4ZMJkxFkoYRxjirKctpm+mBJyyiWG94UlZT3aqX9dhy3GaM92veDwC4QeSw7fGo8i0KMAE/Qe4ViscoGlA7cY+pPZUulppzi7AtjvvMde1lWuC8SeZML5McFIeOV1mDrXcugQqoenXallHu1hORaJWyDro+jap9qR3Rh+5sx+baLu78EPfCXeNvCOkv+HHkuWTIfFERhcgAn64C7cG59A6IsrRTVBF3fsF4hrvSLsPYPTdFsa4W8vUEhOcw/vGlPE7TQgt2tqUAIL6IjbOwrJae6BXSMIl/UEXb529ty0EThbCrlfyT30WDKS1UYauQkwQc9tjebbn9BvqkzQe3+tcASwd7thl9QE4wU94Yxhn8SDqQvMpg5skXonIs6fs1AiXjk9praOPtSaucdlU1gshtPbW06xnQIeeqwWeizZcuMWgaACTNCDchLMUaAvcOzQb/pl00vh++etPi6lwdIqrX+4DS7ABCM4aXQB+ZDLb5VcrdAP+4Uncg0C9r3o1Wtot6omY5qg534Eva+qlUo7CJQRYIJeRo9lKxHQZNBO/Zo7cGN3BY5XNlwqp7i3+snF4loS4W/tau6vhg9LxIgENtP7mh1JpwQW4DT3wKDxhItpEhtaZe3QAUvEi22CHnqsNncxpixBxKII+AswQfc3poXyAn3lQ/SL8LIGcf/td0+N/2hnMY2aT+2nP7ZX3tFc7bXG1Re8ab02X1bQ04MHJmBMAvYd9B1iSiizXDgLJbMVqu6skV+XRo3SftROKZ83or4tpJxmjCWfYqxm+8SQpS9kMGIh4CHABN1DlZihBUJ/Z2hi6ARLxltGy09ZMkbVi8+lBj9WdaMNao8JRv4rm9Pc/dbxNQr9oF94ItcgsJomjjmOWTepwXK4JqfQgzYmialMDJxM6DFl4PQIh8CoUTm+2bFe8xPoC9yliYHjlQ23WNkANS3PBMMP/kKFfsUvPJEjEFhdE45FI8gjuxQ4zT27VWodmkl16Qx7FtsE3YiXiMx5YuB8+gLHIxwCwQWYoAcnJaCDQOhPOx9wyLFMyLFlFq5x2S01wcj5yrq10WqC8ZIa/3NtCdBwVQJcy8FPmrNQ/GzripzVae7af04nyJi+f95ar7EdNAg9Zgs9pmy5cYtAMAEm6MEoCeQo0Bc49sTA8cqGW6RsgJqWt+/Ob1dT201olglG/mt5vAbpU+Tfzep7qA+5rlWrE6tvmRYdBbKaoMtpfdWpHb16DR3bBH1irx0ZYrm+Ie7nbgSiEWCCHs2qIJFhBEJ/2jlxmLbqeCjVI+hmxWnufq+YixQ69MVx/LIlci8C9t4W4xG0XvoS4zJ8yBXjWuk9p9yu5B7j6e22dnKfoIceU/b+imZJBIYQYII+BAx3RyXQFzibiYHjlQ2X8gR9bR0B7CsLwPKTC+gIoE3O/zT5I9yTmQAfcvmtUCbofrZ1RF5c+5ucfp4w1gl6bNfGmBj4xdYXOB7hEAguwAQ9OCkBQwpoZ2w/9zF7yJiKNTFwvJ7DqX92etsHew5Q/4JTKAUmGH7rgQmGn20skbct3gdiySebPPQh1w3qzH3ZdIiO2P5m9RwYtM33qR+LR9qXGZRfTD/9NjGw0+zqXzQ/JRe4b4TLRIAJeiYrMuNu9AXu2ysatD0ROGaZcNa/1LfD8WUAWHZYATvN3S4YR8lXYBZ1bat8u1d7z/iQq/ZVEDSBlYNGqy/YpvU13VHL0ZzmXozZQv+qSV9HCjwJgZoEUp8Y1MRGsxUKhP6u0AMV5t5JU2M7eVLkz7HTDrM4qhGbswYmryqn02LLi3yCC3AWSnDSSQGZoE+iyOKPJbPoxahRsZ7e3uKNZoJeJBR67BZ6bNly4xaBIAJM0IMwEsRRoC9w7ImB45UNl+oV3Af2m5+LGigS7n8mGOEsY420qT7kmjPW5FLOSx9y3aj870m5D+TeTyD5Cbq29dHq0Qb9ehXfP7GNTSYGJuoLHI9wCAQVYIIelJNgDgKhP+Wc6JBjmZA5HEG3/m+nQceYMhAsO6TAJXrkhSEf5YEcBGzb2SGHjkTaBz7kinTF9JDWEtrXTNHDcjEtYj8XN1NMCQ2Sy4KD3FfnXRMDNx56bBk4PcI1XYAJetNfAfH3P/SFSiZG1uXYPqX+/+ydB7wlRZX/H38YwpBzEGQAAUGEEZAchgwDw8AwwzDBERR0XV0TphUDJtxdV0FdV1EMKygqoOQchgySkwoIDEFyThJmhv/vMH2Z+967ocM51aeqf/X51Hv3dledOudbfbvO6a6uLotHFvLbu2xl1utOgNPcu7NJbA+nudt1KAN0O7ahJS+OBtcI3ahye3spy7MQt7qF0AoyZ1Wo26mqtm/ZqQ1uI4HSBBigl0bHioEIJLuCe8YvlTvoYg6nudv9KBhg2LH1Ivm9uDMY/fRdLzDb9cBFrlvw/a72bfwcNYHYfycHREDf20WQWcrMtH1LZfUorukEGKA3/Qjwb/8Kyio+oCyvqriUAvSxCDCWrQqE9TsSuARbn++4hxtTIsC76Ha9yYtcdmxDSx4VukGt9jBGvhuyvL5erd3Mtzl7lEDbd9P2LdvZ8TMJVCbAAL0yQgowJqB9lfMJY31zi8fgtwoKj8xdwX9Beac7n6M16CfcAXwVYk8yEE2RvghMc+YU+6JTTRsG6NX4eart7e5uETYTixSusayM554WrtT23bR9yxq7ik2nSIABeoq9mpZN2lc5n3KEx9siLBpoeAdQg2JnGQwwOnNJaeuaMGbHlAzyYgsuct0GXf7mRR/qUYkAA/RK+HJX9sRZ23fT9i1zQ2VBEshDgAF6HkosUwsB3ElaDA1L1kpzIOhZLWEKcjxdnVYw500RW6PfUln4TouJlpyZEPScljDKcUuAF7nsuoYXuezYhpTsbQGzXLZjbNwABTfMVdhHIU+cxXcTH04rLZb5mFryKIcEVAkwQFfFSWHKBLSvcD6DuyhvKOtYRZy2fVV00azLxeI0aWaycOy+ho8MMAzYOhM5kY6jWY/w92OGNqhgT3d2ixg+sUhhB2XdcM58t2eUmaTqgyljorg6CDBAr4M628xLQPsZIe0pUnnt6FYuxTvoYuv0bgZze2UCDDAqI3QvQN6PPN69lhEqCCf/Dqj9lwhVp8qDCXi6sztYs97fYgvQV+ttTvC92j6cto8ZHAgbTJcAA/R0+zYFy7RPnton96qMU716uzbuAG5XFQ7rdyRwKbZ6ekyjo5LcWJkAp7lXRthVAC9ydUUTzY6RGGMWjUZbKAp918W/jWPSGbp681G0fThtHzOy7qW6ngkwQPfcO9RNe3DQPrlX7aFU76ALFwYYVY+ODvVxB/B1bP59h13clBaB3eHQr5yWSW6sYYDupisqKbJcpdrhK8d291wIefNRtH04bR8z/FHFFpMlwAA92a5NwjDtq5vaJ/eqkFMeHCYhwJDXtDDpE2CAoc/Um8SFoNAUb0qloA8ucv0VdtyWgi0Nt2HZyOyPMUD35qNo+3DaPmZkhyTV9UyAAbrn3qFu2oOD9sm9ag95uzpd1Z72+uI8jWvfwM9qBC6DpKfVpFGQVwJcbNGuZ3iRy45tKMnRBOi4WL0WoGwaCoxiO958FG0fTtvHVERPUU0nwAC96UeAb/u1r25qn9yr0vM2+FW1Z2h9BhhDiSh8xx3A2RDDae4KLJ2LeA8c+3c51zFW9U6KVXHq/RaBaAJ0aBzj3XMB7S2A1fbhtH3Mtw5OfiCBqgQYoFclyPqWBLQHB+2Te1Xbte2rqo92/T0RYKRuozazvPJ4BzAvqbjLcS0Hg/7DRa47IfYWA9EUGY4AA3R71stiDF/QvpncLWj7cPRPcqNnwdAEGKCHJs72ihDQvrqpfXIvYsugshj0RmDDMoM2pvdFbORztDb9egXEPmYjmlIdEZiGcwXHaZsO4UUuG66hpEaxijt+v6MAZItQUJTbkXOPp8X4tB/t0vYxlfFTXJMJcOBvcu/7t1376qb2yb0KwaYMDLwDWOUo6VI3m+Z+cpfd3JwOAXnf807pmOPKEk5zd9UdhZVZuHCNeipMr6dZtVa1/bAqimnfZGmKH1aFOevWRIABek3g2WwuAtonT+2Tey4juhRK/fnzltnvxR2E9Vpf+F+VAO8AquJ0K4wXuQy6Bhe57obYmwxEU2QYArEE6LH/fj09SqDtw3m6+BDmV8NWoiHAAD2armqkoksoW619cq+iXpMGhvdXAcW6XQlciT1PdN3LHakQOAAXuUamYowzO3iRy1mHFFBHHqFynfC73RIKxn6BWtsPq9Jn2j6cJ9uqcGHdBAkwQE+wUxMySfsK+bOO2DTlDrogl+doF3DEPglVcAdwDgz5XRLG0IheBMSJ3L9XAe4rTYDT3Eujq72itn9gYVDsd8+FyZIWYErKfK5kvW7VYjiGuunO7YkTYICeeAdHbp72yfM1RzyWcqSLtSprooEdrRtpqHzeAWxGx6fg6LvrKVzkugdK3eBOMSqUh4C2f5CnzdxlcFFa7vAflLuC34Ke7jK/qozJ9TGkbCvFRUaAAXpkHdYwdTVPnm/AGXvdEb9FHOkSQhUGGDaUr4bYx21EU6ojArvC4V/VkT4pqcKLXHH25hznao+Fftrr6NRhspsAPfPh3lCEoOljKqpFUSQwMMAAnUeBSwJwRheCYprHp6e758K8aQH6RPRpFK/FcfmD6KJUNs39xC67uTkdAvIu4qnpmOPKEk5zd9UduZV5OXfJegrOqKdZ9VbdBOiZZZq+3P/LfE11aBRIAlUJaAZAVXVhfRJoJ6AdwGqe1Nv1LPtZ276yeoSqJ1P69wvVWMPa4R3AZnT4xs0wM6yVuMh1H1q8LmyrbE2BwD8VZJiIQNAna8yMMxEeXqinZ9DFem1frmm+WPgjiC2WIsAAvRQ2VgpAQHvqkfZJvSoCbfuq6hOiPqe521C+BmIftRFNqY4InOZIl9RU4UWu+HrU8x10uXvufpX5nF2e8h10QdBEXyxn17NYnQQYoNdJn233IqB9VdNbgK5tXy+WXvbtjjsLK3lRJhU9cAdwLmw5MRV7aEdHAnK38PyOe7hRgwCnuWtQDCvDc4D+wbAoTFtLPUBvoi9mesBQuA4BBug6HClFn4D2VU3t1T+rWtzEQUHWFZhaFRzrdyTAO4AdsSSz8XRciHkxGWucGQK290MlmYnCFA8Bl1PccRF6GyDcIB6MfTX1tnaMti+n7Wv2BcoCJJCHAAP0PJRYpg4C2idN3kGvoxeHt5nKwjnDLat3y7Vo/pF6VWDrhgR4AcYQbiaajO0Za7bg9Q56SnfPpb/kwrqnpO3LafuanlhRl4gJMECPuPMSV137DrP2Sb0qfm37quoTqv57cIdhw1CNNaUd3AGUV8/8tin2NsxOTm8P0+EnoxnNVziF0bq5rbgL0DG2yYJqkxPrktQD9Kb6YokdpumZwwA9vT5NxSLtq5reAnRt+2Lq9/fHpGxEuvIOYESdVUBVTm8vAKtsUVzkehB1ry5bn/WCE/A4xX0KKCwenIRtg6kH6E32xWyPHEqvRIABeiV8rGxIQPuqpvZzS1VN17avqj4h60/FnQaee/SJy6ui/qEvlhJrJsALL+E6gKzDsa7a0jNVBRjUP9RAZt0ivQXo2r5ck32xuo8ttt+DAJ3kHnC4q1YC2lc1vd1Bb/KgsDqOrJ1rPboSbJzT3BPs1IEBTm8P262c5h6Wd5XWHq5SWbsuLjq/HTI315brQJ63AF3bl9P2NR10GVVIgQAD9BR6MU0btANY7ZN6Vera9lXVJ3R9vhPdhjjvANpwrUsqp7cHJI+LXDID5cqATbKpcgSeQl+9Uq6qWS0Z0xYwk16fYG/vc9f25Zrui9V3ZLHlngQYoPfEw501EtC+qql9Uq+KpumDwgTccRhZFSLrDyNwA7bIs7RMaRDgBZfw/Ujm4ZkXbdHjozwHFTUikvK8gx5JR1HNtAgwQE+rP1OyRjuA1X5uqSpr7QsQVfUJXX8JNDghdKOpt8dp7kn1sExvPy8pi+Iw5hSoOTcOVRurpasAHReb10NPbJRob3gL0LV9OW1fM9HDgGaFJsAAPTRxtpeXgPbrbrxNPfOmT95+0SzHae6aNOfL4h3A+Sxi/iTT21+K2YAYdQfzh6H3FTHq3iCdH3Jm6wxn+miqo+2LVdVN23fyZl9VPqyfCAEG6Il0ZIJmaF8l9XbHenaCfVbUpF1w52HVopVYvjcBBBg3osQDvUtxbwQEeKGlvk4i+/rY52nZ1R10KHxAHqUjLePNV9H25bR9zUi7mWp7I8AA3VuPUJ8WAe1nxrVP6i09y/5/vWzFhOotCFumJWSPJ1N+40kZ6lKYAKe3F0amWoHT3FVxqgtzE6DjIvN7Yd071S30IzD1AF3b1/TTc9QkagIM0KPuvqSV1z5penvOiAH6vMN3etJHcX3G8Q5gfew1Wub0dg2KJWVgFsqjqHpZyeqsZk/ATYAOU6fYm1trC958FW1fTtvXrLWz2Hg6BBigp9OXqVmiPe3I2x10b1el6zp+NsEdiE3qajzVdhFg3Azb7k3VvgbYxQss9Xcy+6D+PuimgacA/cBuSiay3Zuvou3LafuaiXQ7zaibAAP0unuA7XcjoH1VU/uk3k3vvNu9XZXOq7dFOS4WZ0F1YOBEG7GUakyA09uNAecUL9Pc5+Qsy2LhCMiiXn8P11z3lnBxeUfsfVv3EknsST1A1/Y1k+h0GlE/AQbo9fcBNehMQPuqJgP0zpw9bJ0KR0eeR2fSJcA7gLo8Q0nj9PZQpHu0g1koj2P3pT2KcFc9BGahb16up+lhrab67vN2Q73dTND25bR9zXZ2/EwCpQkwQC+NjhWNCWhf1dR+bqmq+d6uSle1p0r9VVF51yoCWHc4ATixt2Irp7kPR+N9y0neFWyQfr9vkK2xmPoXD4riorL4z/t50MVYB2++irYvp+1rGncHxTeFAAP0pvR0fHZqX9XUvupalai3q9JV7alaP+X3yFZlU7ZMIJAAAEAASURBVKU+V3OvQi98XZnefm74ZtliFwJ/wnZOc+8Cp6bNLgJ02L478io1MQjZrLcAXduX0/Y1Q/YN20qYAAP0hDs3ctO0r2pqn9Sr4vU26FW1p2r9/XBHYomqQlh/GAFOcx+GxPUGTm931D2YhfIE1LnYkUpUZWDAS4A+pSGd4e1mgrYvp+1rNuSwoJnWBBigWxOm/LIEtE+a2if1sna16r3S+sD/bxIYib8TyUKXAAKM2yHxb7pSKc2QAKe3G8ItKZoXuUqCM6pWe4COi8kjYNu+RvZ5E/uiM4W0fTneQXfWwVRnHgEG6DwSvBLQPmlqP7dUldsLVQUkWJ+rudt0Kp+jteGqLZXT27WJ6siTae6c8aTDUkPKXzWEVJQxDvWXqSgjlurefBVtX077ZlAs/Uo9nRNggO68gxqsnvZJU/uqa9Wueb6qgATrj8GdidUTtKtukyTAYPJPgNPbHfYRZqE8BbUucqhaE1V6CP3hIWA8qEHwPfBux63ty2n7mu268jMJlCbAAL00Ola0JIBBWO5YzFVsQ6akeUoM0If3hpyPpg/fzC1VCOC3dAvq31FFBusGIcDp7UEwl2qE09xLYVOv5GF6+2Kwai91y/wK9Baga/pyczNf0y99atZYAgzQG9v1URiueWVzgey5MS+GM0Dv3BOc5t6ZS9WtDDCqErStz+nttnyrSj8VArwtllXVphjr1x6gA9oE5CYtaOomQM98uAUUD1xNH1NRLYoigYEBBug8CjwTSPk5dAbonY+8DTEIb9Z5F7dWIMBp7hXgBajK6e0BIJdtAnfZnkbdC8vWZz01AjepSSovqCmrt7cIuQnQoZD28+faPmaLGf+TQGUCDNArI6QAQwLaVzeXNtS1qGgG6N2J8S56dzal9iDAuA0VJTP5JMDp7T77pV0rzkJpp1HP5z/X0+y8VnHxeCl82rVOHWpo21OAru3DafuYNXQPm0yVAAP0VHs2DbteUjZjeWV5VcQxQO9O7yA4Qgt13809JQkwwCgJzrgap7cbA1YSL9Pc6dArwSwhRsbMO0vU06wyGcK07+Jq6mchy1OAru3DeXuFnEX/UWakBBigR9pxDVH7SWU7tU/uVdRjgN6d3srYtUf33dxTkgCnuZcEZ1yN09uNAWuIxyyUZyHnAg1ZlFGKwHXogzdK1dSr1KTV21vUUg7Q5Q0NTCTgkgADdJfdQqUyAtonTwbo8RxaM+JRNQ5N4dzKSu6yojuTLwKc3u6rP3ppw1kovejY7qt7evuKMG9HWxNdSn/GkVbaPpy2j+kIFVWJnQAD9Nh7MG39U76D/lzaXVfZun2z5/0qC6KAQQQYYAzCUfsXmd5+du1aUIG8BE5DQU5zz0tLt1ytATpMkcXhFtQ1yb00mbGg7YdVMVo7QPdkWxUurJsgAQboCXZqQiZpX93UPrmXRo27mbJ6KIP07gQXxa5J3XdzT0kCnOZeEpxRNZneLkE6UwQE0Fdyzj4vAlVTVNFDgJ4i1142PY1jfnavAoH3aftw2j5mYBxsLmUCDNBT7t34bdO+uql9cq9K+LGqAhKvz2nuyh0MZ+uvEHmTsliKK0+A09vLs6urJmehhCf/D5y7Hg7f7LwWMZtrdXzasq72a2z3iRrb7tS0tg+n7WN20pnbSKAUAQbopbCxUiAC2lc3tU/uVTE8WlVA4vW3h2O0ZuI21mEeA4w6qA9vU+6cnzt8M7c4J3A69JMZUEzhCNR993w6TF0gnLluWnrcjSbzFNH24bR9TGe4qE7MBBigx9x76euufXVT++RetQd4B703QXGI+E703ozK7D2lTCXWUSdgvno7LnBtiryYuuYNFog7ufIGjnMajKAO06+ro9G2Npu4eruYn3qAru1jth0y/EgC1QgwQK/Gj7VtCWhf3WSAbttfFtIZoCtTRYBxN0TeoCyW4ooTCDG9/VCo1dTgoniP5K/BWSj5WWmUvFZDSBkZuMC1LuptUqZuAnVSn+Ku7WMm0OU0wQsBBuheeoJ6dCKgffJkgN6Jsu9t68FBauKzf9a9wgDDmnBv+ebT2/G7kRko45F5kat3X5TZewYqvVKmIusUJvA6atQWoKNtmd7e1JT6HXRtH7OpxwntNiDAAN0AKkWqEdCefuQtQOcz6PkOFQYY+TgVKcXV3IvQ0i9rPr0dKu+GvBryDgjWV9Y3obkSMQvlRVjP1+OFOQSuB++XwjTVsZWJHbc2Y2PqAbq2j9mMo4JWBiHAAD0IZjZSkoD21c1ls7tKJdVRr8Zn0PMhPQj9NiJfUZbKQyCb5l73c515VE21TIjp7a2p7fLu5g+kCrJGuzgLJQz8mWGaGd4Kxp1NsXXD4Xsas8WNj5L5bssqk9f2MZXVo7gmE2CA3uTed247ggiZBvqyoppyvC+jKK+qKDeDX1VDjOvLzIexxm00UTwDjHp6PcT09oVg2rg28w5s+8yPOgTOhBjpSyZbAjNtxfeUPqXn3vR3PuDIRPHdNGOWlzMf05GJVIUE5hPQPNjnS+UnEtAjoH2F09M090f0MCUvidPc9bv4FH2RlJiDQIjp7XJBa4U2XUbjDtTmbd/5sSKBbNr1WRXFsHpvArOx+6reRUz3TjKV7l+4pwBd23fT9i399yY1jIoAA/SouquRymo/I7SiI4oPQxdZAIepP4F9EGB4mv3QX2PnJRBg3AcV61x8yTkhM/VCTm9vN4IXudpp6HzmLBQdjt2kyPPnL3bbabkd4812kL+mZRvOZb8K/R53pONKyrpo+5bK6lFc0wkwQG/6EeDffu2rnG4GXDgec4D/Qf9d4ELDRaDFZBeapKUEA4yw/Rlierv8VuQO+tA0EUEHx/yhVKp9lzvomo9hVdMmvdqX1mhSaw2HGlWotekH4KO8UasGgxt/++Cvlb9p+5aVFaIAEmgnwMG6nQY/eySgfRId5cxIuYvJlI/AjHzFWKoAAa7mXgCWQtEQ09vl1WpLd9BVVnTvFLh3KMpNeQgggJHgXJ5FZ7IhMNNGbG+p2YWsCb1LJb/3AWcWjlLWh3fQlYFSnC4BBui6PClNn4BMA9dMozSFKciapSCjKSK2geO0dlOMDWEnAgy5QHR1iLbYxpsEQkxv77WwFae56x+InIWiz1QkyvPnV9qI7it1F5RYtW+ptAvc78y8Ucr6cA0gZaAUp0uAAbouT0rTJzBLWeQoZXlVxfEOejGCvItejFee0gww8lCqXibE9PaRUHP3HqrujYtci/fYz13FCZyNKi8Vr8YafQjciAuIL/QpY7W710Uuqza9yU39Dvosb8CpDwm0E2CA3k6Dnz0S0A5g13Rm5Cxn+nhXZ5p3BSPUj9Pcw3RaiOntsuq0BOndkgTnDD660SmxHUGkXHg5o0RVVulNYGbv3TZ7cQFLXlG4r430qKSmHqBr+5ZRdS6V9U+AAbr/Pmq6hrOUAXgL0DlIFOvgd8CB2qZYFZbuRQABhkxlrGsqaS/VUtsXYnp7noWtOM1d/8jiLBR9ppfoi8wlcW+U0n6lV66GnRXyNsVde5G4Wc54Ux0SGESAAfogHPzikIB2ALsYAryVHdmpbZ8j08xU4TR3fbQMMPSZtksMMb1dFobbub3RLp+3wzlQFoxj0iNwDkTVNR1bzwo/kl6BKnWt4J7nIpcfUnaa3G0nupjkzGdbrFitvqXpe/VFxAJ1EmCAXid9tt2XAO7uyTtQU17J/VHYJ84IU34CB2LAXjh/cZbMQUCmub+RoxyLlCNwBs5l1s8pS2CR53ch4/4HypnBWp0IoG/lHH56p33cVorA5WAqF7WCJowri6JBuYPe9CRvJ3jIEYRRyro8lfmWymIpjgT0CDBA12NJSXYEtK90jrJTtZhkDBISFGnbV0yJ+EovC5XHxae2X41xHD4I7a7wq2H0moWYoVDkzt/U6In6MyBEH/uz2kaj82zE9pW6H0os2bdU+gXuzHwTL5aOUlaEPpcyUIrTJ8AAXZ8pJeoTmKUscpSyvKri/lpVQAPr8zla/U5ngKHPVCSGmN6+AtrZvoD6G+Bu4ZYFyrNofwISVD7fvxhL5CBQV4DOBRTndc6dOfooZJFRyo3NUpZHcSSgToABujpSCjQgoH21c00DHauI/EuVyg2tuxcCDC7ko9v5p0LcG7oiKQ0EQkxvl7cbLFiQNi9yFQTWqzjuOL6K/af1KsN9uQj8Ayxvz1VSsRDGE7lz3usVhYqtuRflLUDX9tm0fUr3HUoF4yPAAD2+PmuixrOUjR6lLK+qOAboxQnKs7ZFpvQWb6FhNeAUyzOHlzXM7BDmhpiZUOa3cACCkqJBfQheMbcRoq9j5pNH9/PyFDIoI68olGfQmQYGvAXoo5Q7ZZayPIojAXUCDNDVkVKgAQHtq52jDHSsIpIBejl6XM29HLdetRhg9KJTfF+I6e2yInuZ6eqroN4+xU1ijR4Ezse+53rs567+BOoK0Mtc5OpvTZwlUg/QtX3KOHuZWrsmwADddfdQuYzALGUS2tOlqqong+HcqkIaWH8L3AFct4F2W5rMae66dENMb5ep6guUVJvT3EuC61QNs1Bew3b5DTGVIyDj4IXlqpavlT0utVN5CcnVvMuZRdo+2yxn9lEdEhhGgAH6MCTc4JDALGWdRmJAXklZZmlxcOpeQeV7SwtodkXeRVfsfxyLD0PcTEWRTRcVYkZClTt/Y3Eu5KrVukdpiD7X1diPtOtwDnq6BnXkN7RQDe16bPIh9IG83tZFyny1kcrKzFKWR3EkoE6AAbo6UgrUJoDBQqaJPqYsdz1leVXFcZp7OYLTMYCXvXtYrsX0azHA0OnjENPb14KqoyuouxjqTq1Qn1WHE7gAm54ZvplbchCoa3r7lBy6NaVI8AX6+oBdv8/+orsfy3zKovVYngSCEmCAHhQ3G6tAQPuZoXdX0MWiKgP0clRHoVqR10uVa6VZtWSKLh+5qN7nIaa3a8wg4TT36n39lgQ4/6/jC6e5v0Wk0IfgATou8K4GDbcupGXahW92Zp62r6btSzrDRXVSIcAAPZWeTN+OWcomap/0q6rHAL08QY0gpXzridVEgPEoTLokMbPqMCfETIQq09tbTLZBkPL21hf+VyEQou9VFHUk5Fnocm0N+sgrCukLzwefeoA+a76p/EQCfgnwpOS3b6jZYALaVz29Bei3DTaX3woQmIgAg6/HKQAsR1EGGDkg9Sgi09vP6bG/8i4c86Mh5J2VBc1bYO4QBTkUMZ/ARfhYx7PU8zWI79N5uDg4pwa1NS5y1aC2WZOpB+javqRZR1BwswkwQG92/8dk/R3KynoL0MW+V5VtbIq4pWHo+KYYG8jO09AOp7mXhy3T218uXz1XTc3AYnKuFlkoF4FsmvufchVmoRaBs1ofQv3HRa610damodqLoB05Z93tTM+NlPXR9iWV1aM4EphHgAE6j4RYCGjfYV4ag/MaXozPHLpbvOgToR58jlax03A8yqKMcheQqRyBEDMQ9i+nWsdaG+B8uE3HPdxYlkCIY6Csbt7qycVA0xknXQye3mV7UzffinO/mwuzOCfJozdyAV4zafuSmrpRFgm8RYAB+lso+ME5gb9BP1l8RzN5u4t+g6ZxDZO1BwbzFRtms7W5DDDKEZbp7eeWq5qvFo71rVBS+00UvMiVD3/eUhej4FN5Cze83LUIDJ+sgcHEGtr03GTq09vFhxRfkokE3BNggO6+i6igEMDg/Rr+aZ9YvQXo17O3SxOQd9jydVGl8XWsKNPc53Tcw429CIRYvf2gXgqU3HcAAn++C7okvKHVMGbNxrY/Dt3O7x0JnNlxq+FGHOubQLw3H8DQ4lyiUw/Q/5b5krlgsBAJ1EmAAXqd9Nl2UQLaU5O8Dc4M0IseEYPL8w7gYB6VvsGReQICLqwkpJmVTwpgtub09pa6MgNl39YX/lch8HsVKekLCf78OZDy3efDjytvAbr28+faPuRwgtxCAkoEGKArgaSYIARuVW7FW4Aur1p7RdnGJonbDHdFNmySwQFs5TT3YpBlevvZxaoUK41jfAxqyLOZFokXuXSpzoQ4udDF1J3Ag7gYWMf6K5O6q9TIPTL9u45+6AVb20fT9iF76c59JFCJAAP0SvhYOTAB7ZPrOz1N6cymRHq7gh24iys3xwCjMsJBAk7HN5mqy5SPQGyrtw+1ak+cE7UXZRraRmO+45w+B8ae0hiDyxl6Rrlq5WvhGN8atdcuLyHJmjfjeHVzgyDzzTReI9neWdo+ZLtsfiYBVQIM0FVxUpgxAe3pSQtD3/WNdS4q/oaiFVh+EIFpGNgXGLSFX0oTgMMmCzddUFpA8yqaTm/HsS1j9nhDrItC9jRD+U0UzVkovXtdLgKGThZrOIS2Qbu9q7UFVpQnvpn4aJpJ24fU1I2ySGAQAQbog3Dwi2cCCBYegn7PKOuoPYWqqnp8Dr0awTVQfadqIlh7CAEGGEOAdPkq09utXxW1O9pYpUv7Wps5C0WL5Dw5l+GfvLaQaTiBF7DpkuGb7bZkF3APsGshWsneAnRt3+yZzIeMtoOoeLMIMEBvVn+nYK32FCXtQaAq42uqCmD9gRlkoEqA09zz4Yx19fah1m2FIGbU0I38Xo4AggJOc++O7jzwkTe0hExyAfdtIRuMpK3UA3Rt3zGSbqWasRJggB5rzzVXb+0pSq4CdDgrf0PXclGhasf3BAQYI6uJYO0WARyTT+Pzea3v/N+VgPX09hFoeVzX1nV3fEBXXOOlcRZK50OgjuntXL19eF88gvP8/cM317pF2zdjgF5rd7LxogQYoBclxvJ1E9A+yY6u26AO7V/eYRs35SewJIrul784S+YgwACjN6QQ09v3hgrL9VZDbe9kNUkUJATknP4oUQwiIDMLTN94MKg1fMGF24Xwj2PDUDADA97unouG2r6Z9s2d4RS5hQQUCTBAV4RJUUEIaAfoa2DQXj2I5vkbYYCen1W3kpzm3o1Mue1noJq8hoepM4FUpre3rFsP58XtW1/4vxoB3J2cCwknV5OSXO0rweWpwFbtifZWCNxmDM25CtAzn2wNZXDavqOyehRHAoMJMEAfzIPf/BO4HSq+oazmNsryqopjgF6V4MDArhjkrRfTqq5lJBLgSMvijOdGom4dalpPb5fV1ccGNux9gdtLvTnOQhncw6cO/hrk20FBWomvEVcBOvBp+2TiM4rvyEQC0RBggB5NV1FRIYBA4SX8u1eZxrbK8qqKuxkCXqgqpOH1F4T9fF2U7kHAAKMzzxDT2/dH0/LoRsgkaznIc+9MOgSuhJiHdUQlISVogI5jeRFQG5cEOV0j5Pzl7e0x2j7ZvZnvqEuO0kjAkAADdEO4FG1GQHuqkvbV2kqGYyCRZ/OuqiSElYUA7wDqHgdnQlzoFZd1LbCRltr09hal5fFhv9YX/q9GAOd1TnOfj/BW8Lhv/tcgn/ZFK0sFaSmuRq5CX7zqTGVtn0zbZ3SGi+qkSIABeoq9mr5NNyqbOBpX10cqy6wqjtPcqxIcGNgE/fru6mIoQQjAiXsW/84hjWEErKe3L4EWdxvWapgNvMily5mzUObxDHr3POtCrt7e+Vi+uPPmerZmvtho5da1fUZl9SiOBIYTYIA+nAm3+CcgUwU1k6zsuoWmQAVZDNAVIELEDB0xlJIRYIAx+FAIMb19EppcbHCzwb7tAYd52WCtpd+QzIx6KH0z+1oYNEDHMSwXuWSBOKbhBFwF6FBPfDHxyTSTts+oqRtlkUBHAgzQO2LhRucEroV+s5V11J5SVVW9P0OAt2lnVW2qo/5UOGc8z+mRl2nur+iJi15SqtPbWx2zMD5Mb33h/2oEMAtFFqtq+mruD4DDTdVIFq59AGrUdZGrsLIBK8haN96eP9f2xcRXFJ+RiQSiIkDHNaruorJCAIP7y/h3szIN7UGhknqwUYIg3kWvRPHNyqvh767VxVCCEMBx+Tz+cZr7/MPBenq73L3eeX5ztXziLBRd7E2fhRL07nnWdVy9vfMxfBnO6do3Ozq3lH+r9gJxN2c+Y34NWJIEHBBggO6gE6hCKQLaU5a2xp3WBUppYlfpPDvRjZLM52h1u7vpAUaLZojp7RJYaE/3bOmf9//mODeuk7cwy/UlcA1KPNi3VLoF/hTSNBy7cpFrl5BtRtSWq+ntmQ+2lTK/K5TlURwJBCHAAD0IZjZiQED7pLscdHyngZ5VRDJAr0Jvft39MfAvPv8rP1UkcBbqywyPpqfUp7e39+8H2r/wc3kCuJsn09ybepHrSdgeembYZLQ5onyPJV3TVYAO0uKDiS+mmbRv5mjqRlkk0JUAA/SuaLjDOQGL15BpT62qhBCO3G0Q8EglIawsBCQ4l2cQmRQI4LiU5xYlSG96sp7evjIAezknSZDDpEegqQH66Th/yGtEQyau3t6Z9lPYfEvnXbVttTjfWfiKtQFiw80hwAC9OX2dlKUY5B+GQdrvUXX1HHrWYbyLrnPk8jlaHY4tKU0NMFr2h5jePhWNLdhqsOb/62AWypiadUimeYxff4Yx9ydjUH5DQk9vXwWqbZdfvUaVPB/Hoczm8JS0fbD7Ml/Rk43UhQRyEWCAngsTCzkloD11SXtw0MDGAF2D4sDATggw3qYjilJA4GzkJk9zb9L09tYBz7UcWiR0/jftIpfMvLlAB11uKXKRi35uZ1weZ0Fp+2DaPmJnktxKAgYEeOIygEqRwQhon3zXRxC3QjDt8zUkDs3cfEVZqgcBOdfxdVE9ABXZhbsSL6L8GUXqJFbWenr7GuD1XmfMZC0Hee0akw6BpgXo5+C88aoOutxSDspdslkFxac415PJme+1vrJO2j6isnoURwLdCTBA786Ge/wTsDj5WjwDVZokHBp5TuyG0gJYsZ0A7wC206j+uWkBRouYvObxnNYXo/9yMcnbWyVkNewJRvY2TizO7fL+ae3HtDxzPCWkcgj41kJ73i5yhUTQq61rMt+iV5nQ+yx8LwsfMTQXttdQAgzQG9rxiZh9B+x4TtmW3ZXlaYjjNHcNigMD74LT9h4dUZQCAhKkyrPYTUtnwrl9ydhor3f+uJaDbsc35SKX3DmXx2JCJpneztSZwFmdN9e6Vdv3Et9QfEQmEoiSAAP0KLuNSgsBOMkyTetqZRp7KsvTEOdxMNWwqw4ZDDCUqGdB6ulK4mISYz29fQPA2NgpkF1xkWt5p7rFqFZTAnRZkEweiwmZJoVsLLK2znSor7bvdXXmIzo0lSqRQH8CDND7M2IJ3wS0pzCtDQd0XWcmXwt9+Lo1nU6Zgv71sjK2jkX1SmlKgNGiHGL1dq93z4XBCGQ+KtI6Gir+RwBxI0TcU1FMDNVDr96+EaBsEgOYGnR8CMfdrTW027XJzOdau2uBcju0fcNyWrAWCZQkwAC9JDhWc0PA4iSsfSW3EiwMpvIqlFMrCWHlFoGV8WGP1hf+r0xAFhqSZ7KbkkKs3n6Ac5ichaLbQalf5JKZbqHv2E7R7aKkpHmckWfhc1n4hkkdCDTGNwEG6L77h9r1JyB3l2f3L1aohMVgUUiBDoWD3oHo0H5Km3gHUKk3cfFIgvPTlMTFIMZ6evumgPAu5yDegzte2qstOzfZVL3UA/TLcZ54wpTgcOGTh2/iloxAEwJ08QnFN2QigWgJMECPtuuouBDIAgRZDVczjYEDuoimQAVZMyHjWQU5FDEwMB79uyRBqBFIPcBogWr69PYWB/l/SPsXfi5PAGPYzah9d3kJ7msGvbiMc/sWILKOeyr1KFjHu+h7Wor+WhQFdupZqPjO6zPfsHhN1iABJwQYoDvpCKpRiYD2+zxHQpsdK2mkXBmDzesQ6fHKt7KlQcQthla4gJAeannLQOgFoPS0zy8pxPT2WF5jNhmOtbfXwOXvSX8lU77IFXohSc9rONR95MkbKF6pW4kh7e+A7zImayZtn1BTN8oigVwEGKDnwsRCzglYnIw5zd15p1dUj9PcKwJsVYfDJ3eWmzDN3Xp6+zbgGMudv1HQdWdkJh0CqQboN+H8EOxd79lFo4k6XZKkFNNzWEliFr6WhU9Y0jxWI4FyBBigl+PGWr4IXAd1nlJWyWLQqKqiDDqvVBXC+m8S2BHO3NvJQo1AqgFGCxCnt7dIzP/PxeLms6j0CUGsrKp9ZyUhPisHnd4OBHI3dg2fKGrX6iVo4DFw1fa1xBcUn5CJBKImwAA96u6j8kIAzs1c/JNptpppA28BHOyUAfZ8TSMbLEum505vsP3apstxKc83pppkaqj8/kxSdudvfxPhdkJlLYdF7cQ3TvLvE7Q4dIDO1du7H0RyDpMLjW5S5mNtoKzQeZlPqCyW4kggLAEG6GF5szU7AhZXhrWv7GpYf4qGEMp4kwCnuSsdCHCIZGZHyq8CtJ4hIIskra7UHaHELI2GvL8SLhQLjXasjzENHYvIuAfnhduLVKhSFsHegqjP47E7xJO776ptj4WPdU5t1rBhElAkwABdESZF1UpA7qDL+8I1k8XgUVU/uSPh6ip4VYNqrP9OOHXvrbH91JpOLcBo9Q+nt7dIDP/Pae7DmZTagmD2DlT8a6nKPiuFvnu+OzCs4BNF7VrJ6zDPrl2L4Qpo+1jiA3KW4XDO3BIhAQboEXYaVR5OAM7N49h6w/A9lbbsggBuRCUJypVhp0wjPkNZbJPFMcDQ6/0LIOp5PXFuJFlPb5c7f+PdWFtMkZ1xjlyxWBWW7kEgpWnuoQP0g3pwbfqus+E7SJDuJmW+1S7KCt2Q+YLKYimOBMITYIAenjlbtCOgPbVpKagqKyt7S7/xplDE+hwER2GhiPV3ozoco1ehTGinPIT91jMD9oARK4UwxKAN+e3wIpceWOtjTU/T3pIexe5rehfR24tz+MKQtp+exOQkeTyuxLcSH0szafuAmrpRFgkUIsAAvRAuFnZOwOI59L0c2ix2Pu1QrxhVkimRY2NU3KnOHh3BKqg4vb0/PS7M1Z9RrhK4yCVT3IM9t51LqXKFToMtsnhrqLQPGtIO9kLpbt3Os2gg9Lvo89hk4VtZ+IB5bGEZElAnwABdHSkF1kjgWrT9jHL7E5XlVRYHx+c1CPH4PtPKttUkgIvF6YG/EKKe0xNXuyTr6e1y529c7VZWU2Az3MHcuJoI1m4jkMJFrtALRvIiUdsBNOTjH7LZTUM21/5V27cS3098QCYSSIIAA/QkupFGCAEMQnPwT3uBkHXgfG7mkDCnuet1yjj08TJ64porKbt49MeECFgHS3LnL4Vjj9Pc9Q5662NOT9POkmSdlIs779LfinP34pA6Vl9yMhJ/7c2SzKdaR1mv8zMfUFksxZFAPQQYoNfDna3aEbCY4nSgnbqlJV+Bmg+Urs2K7QQWwRePfdyuY0yfYw8wWqw5vb1Fov//A+F0L9C/GEv0I4Ag406UubVfOcf7ZdaJzPIKlfZHQyNDNRZZO/Kquysd6mwx3lr4fg7RUaWmEGCA3pSebo6dcpLWft3aJG/4MOiKjb/1plfE+nCau17nXQRR8txj7Ml6evtiAGTxHGYd3NdAo7vV0XCibcZ8kSv0QpEHJXoMaJh1vIYQAxnaPpX4QwzQDTqKIusjwAC9PvZs2YAAAldZPfZmZdFr4e7QFsoyNcRxmrsGxXkytkUfr6UnrrmS8Bt8HdafkgAB6yBpAhgtkQCnlgmc5t4iUf2/9bFXXcPOEuRNDsECJZyzl0V7vDDUuS9kq7sAPfOltMfamzPfrzsJ7iGByAgwQI+sw6huLgIWDoLFlKxcxnQrhAFJVvvloijdABXbLtNzeRe9GLNepWMNMFo2cXp7i0T+//vC+ZZZAUwVCeDcfjdEaF9orqhVruoXQnd5Bj1UkoXGZKFFpuEErkBf3Dt8c+1bLHwpC5+vdlBUoNkEGKA3u/9Ttf40A8Mmwfn0+IzlzwxsbarI6U013MDuSyAz5lcBWk9vl1dC7WrAvU6RS6Jx7amrddpTd9sxXuQKPb2dq7d3P0p/3X1XPXsyH8riHGHh89UDia2SQEaAAToPheQI4Kqx3FW+X9mwt0PelsoyNcT9DkJC3rHQ0NmrjHXhQGztVbmY9MJvMPZp7tbBkTipi8bUpzl15TT3nKByFLM+BnOoUKjIXJQ+o1CNCoVxrl4J1XeoICLlqi/COPENvCXxocSX0kz3Zz6fpkzKIoHaCTBAr70LqIARAQvnZrKRrqXFYmB6CZW5WFxpgsMqcpr7MCSlN1j8BksrU6Aip7cXgDWk6BgETqsM2cavJQjg3H4Pqt1YompdVa6Ezo8HbFzuni8YsL2Ymvot+sLjhXsLHyrWcSam44m61kCAAXoN0NlkEAK/N2hlYjZFy0B0JZGc5l4J36DKk9HHfKZxEJLSX2ai5lOla9dX0Xp6+/IwbUx95pm2LAHT+01baJbwmIKP0NPbD2rWoVDI2mMLlQ5QOPOdZM0A7WTh62nrSHkkUJgAA/TCyFghBgK4enwD9JQ7EJppdQjbRlOghqzM1ps0ZFHGwHJgsDc5VCeA43I2pJxcXVJwCScZtyiBxULGbdQpnoGTHv2YAvRgzwEj2JNp0jJdmmk4getw7vU480J8J/GhNJO85118PSYSSI4AA/TkupQGtRGwcG4sViBtU7n0x5+WrsmKQwnMGLqB30sTsPgNllYmR0WZ3n52jnJViqQewI5GAPWeKoBYdx4BBB/34dN1EfCQ11zdG1DPqWjL46KtARF0bcrd3fNMUwvfKbbxpWuncQcJDCXAAH0oEX5PiYDF1CeZ5u7xdyPPocvz6EzVCYxFH8uddKbqBC6FiCeqiwkmwXp6+6qwxN0sHAO6vMilBzWGIORUPXNzSZLnz5mGE3gOm04cvrneLZnPxOnt9XYDW4+MgMdAIzKEVNcrAVzRvwW63aWs32qQt52yzMriYOvzEGJxQaKybhEKkGfQU7/LGaRbcFzOQUMxTXO3nt4ud/6aMO5OcXohM8hxr9yI9TGpoW6w589xXK0PhTfWUDpBGcfjnPuyQ7vEZxLfSTPdlfl4mjIpiwTcEGiCo+AGNhWphYBF0Or16v0PayGcZqNczV2vX2O4AyjWcnq7Xp+vDFF76IlrriQEIfLK0GsdE7gPOt4aUL9pAduKrSmv09stfCYL3y62/qa+CRNggJ5w59K0NwlYBAdyd2ikN75wkm6GTjO96RWpPluhj9eNVHdval8OhR7zplQHfaynt6+DNjfv0G6qmzjNXa9nLcYxLe3+qCUopxyLZ5lzNu262GXwAW73pmHmK8nMIe3k+TehbSvlNZAAA/QGdnqTTM4GrL8o27w05Hl1Eo5RtrXJ4ngXXaH38RuMZZq79VTipj02MQ7O+eIKhxBFDAzIsfmGUxDBnj/H8bQZGMgUd6bhBI4evsnFFvGVllLW5C8eL0Yo20hxDSfAAL3hB0BDzLe40nqYU3ZnQK+Qq+k6xaCi1nQ4hFwpWAXlgMVvUEezeVI4vV2T5jxZEpxP1hfbPIkIRh6E1dc4tPxx6HRVQL2adpErL9p7UPD0vIUDl7PwlbyPJ4ERs7kUCTBAT7FXadNQAhbPKm2D4G3DoQ3V/R2O3FzowGfRdTpiLYhxtyCgjmnBpVyBFh8N3mr+Bq2nt8tdv43yq5NMSc5C0etKj0HJadmYo2dlb0mTeu9u7N7vB+6HXKAzH2mbXIWLFbLw6YppwNIkYEyAAboxYIqvnwAGrr9Bi9sMNDnUQKaGyF9AyAsagihjgAGGwkGQOY/WU8iraGqt2/QqykVcdwc46dqrN0eMo5Lq8jYEb9PcQ67eLhdL16xEMM3Kz8KsXzo1zcJHujXz6ZyaTLVIQIcAA3QdjpTin4DFFdcZcD4X8WY6Bi955ZoE6UzVCUzy2MfVzapFgsc7gAIixPR2i3cA19KJBRsVH+PggnVYvAMBnNcfwuaQ08k7aDFok1wEvnjQFtsvFiuB22ocRvrPcGy8GKap/K1k4+aM/DVyl/Q6juQ2gAVJIA8BBuh5KLFMCgQsAvTlAWZ/p3B+CL3mOtUtJrWWgbL7xqSwY10luHjEoX7W09tl5fZ3OrQ7lEoMrPRIewpOzkZg+Kqead0lIdgTX3VC9xKN3TMblstY7zGJbyQ+knay8OW0daQ8EqhMgAF6ZYQUEAMBOBJ/h56XGuhqsQBKZTVhr+dFYyrbF1iAxV2AwCbU3xyOSblg5CnAaEGxnt7e9IWtNkKAJRcpmKoTkGnuXi68BpveDpt3RV6lOr7kJJyM86osIOgxWfhGl8Je8eWYSCB5AgzQk+9iGthG4Gdtn7U+7gTnU95v7DF926NSEeq0B/p4xQj19qiytwD9ZUA62xgUF7YaGOBFLoWDDMHJwxBzpYKoqiJegwDr3027jk2/yNXOov3z99q/ePmc+UQ7Gehj4cMZqEmRJFCdAAP06gwpIR4Cp0DVZ5TVlddwfVBZpoo4OHN/hqALVYQ1W8gImE8HUecYuBpi/qEjSkXKWfidvKQiqYMQOKrbYfPbO+xq2iZZy2HBphltZK+Hi1wX4XfzgpF9g8TiuJHz736DNvKLELgAfXCdUxTiE4lvpJnEdxMfjokEGkGAAXojuplGCgEMZq/g3wkGNA6BE7GQgVwNkd/SEEIZvAOocQzgNyirUHsIMFrmcHp7i4Ttf5mePNa2icZI9zDNPeT0djlulm1M7+Y39Jv5i4YrmflChxi0eELmwxmIpkgS8EeAAbq/PqFGtgQspkiJ87mPrdrlpGNAm4macteSqRqBzeF4NHmhr2r0Btf2EqCbrt6O40XGV6+LSA7ukTDf+MpCBc44pz8KMZcpiCorQp6BP71s5RL1uMjgcGhX4Dio8xgYrtH8LeILiU+knSx8N20dKY8E1AgwQFdDSUExEMCgdhv0vNZA18MMZGqJ5F10HZJ8jlaHo/z+HtQRVUmK6ert0GxnZL4DfH4X7YOLFkvO/8pPFQjUeZHrKoyjj1XQPXdVHC+LofDeuSs0p6DLu+cZfgtf6NrMd2tOD9PSxhNggN74Q6CRACyuxO4JZ2INjzQxsJ0FvW72qFtkOk1DH2s/VxcZgurq4nj0Ms2d09urd2cRCRJsHVSkAst2JfBH7JnTda/tjlNtxQ+SLs+eLzFoC79cj3PoeR4xZD7Qnga6WfhsBmpSJAnoEWCArseSkuIh8Huoqr3AjfyW/tUxgqMc6xaLarLY15hYlHWuZ513AAWN9fR2WZNivPM+qEM9TnNXoI4ATe5gX6ogqoyIkAE6L+gM7yHPd8/FB9KOK8RXE5+NiQQaRUD7h9QoeDQ2TgJwbl6E5icaaP9hXEH2erVfVj+908DmpolkgKHQ4/gN/hliHlAQVVaE9fR2uYu0QlnlEq63ndeZRhEyr+Mi16347d4TghWOk6XRzh4h2oqoDXlEL+Tz/7nRZL7Ph3NXyF/wxMxny1+DJUkgAQIM0BPoRJpQioDFlClZafYDpbQxroQBThb24bPo1TlPhCMiU3WZqhOo864Ip7dX778yEuQRkYPLVGSdYQTqmOYecvX2A2DxIsOsbvaGb2Esl0eEPCbxfSxW27fw1Tzyo04kMIgAn6cchINfmkQAgZY8l72Jss33Qd66GETrej6wqzmwVy7IyRX4DbsW4o48BKaify1mYORpO5kyOB43hzHX1WCQTG9fEX1o8v5z2CVBhUxBljuATMMJ/BXseQ4azqXwFhxrF6DSroUrlq/wHvSdjJvmqQbbzG2q2MCtqD8a/N0F6OirBaHb3chrVbRxaPVbYO/ooRv5nQSaQIB30JvQy7SxGwGLK7MyQMmVf3cJA53cRf+SO8XiU4jT3BX6DMfj9RAzS0FUURHW09vHQSEG5917ZQM49Ft13809BQiEnOY+C7/ZUMH5imAwpgCHJhT9Evi7C84z8OLzaAfnItrCR8tU5j8S8E2AAbrv/qF2tgROgHi5m6adDtcWqCUPA7xMUZTAiKk8gd0RYKxcvjprthGoY5o7p7e3dUBNH3mRSwe8THOfrSOqrxQZO0KlyWhIFlpkmkfgGozdZziGYeHziG8mPhoTCTSSAAP0RnY7jRYCGPCewz8LZ30LBHDbO6b8Rce6xaCaTOebGoOiEegY8g6g4BCn72wrLvjdLw7Ze1nJT0juJLBiAFaxQzGGPQURF1cUk7d6yACdq7cP7hW3Y3bm62wxWF2VbydlPpqKMAohgdgIMECPrceorzaBn2oLzOR9xkhuZbEY9OS5xUsrC2q2gBnNNl/HehyLN0LSvTrSckmxnt6+P7QYmUuTZheSKcz7NBuBmvUhLnI9AW2vUtO4hyAEfKtj9zY9ijRt14U4T17i2GgrX8fKN3OMkqqRwHwCDNDns+CnBhLAwHclzLaY8j0OjsZ6jpG6vSLvmFm7aqPRvxu1b+Dn0gRCTnO3mDHTbviU9i/83JMAp7n3xJN7p9zZfj136XIFT8dYOadc1cK15De0QOFa6VZwO1ZnPo6suaGdrs98M225lEcC0RBggB5NV1FRQwLfNZAtDsanDeSqiMTgJ3dDzlIR1lwhvIuu0/ch7gCKptbT25dGG7vqIGmElLFw8IUZUwUCOJc/jeoXVRCRp2rI6e28yDW/R/6E/r1u/ld3n8THsbiY8t/uLKVCJBCYAAP0wMDZnEsCJ0Or+w00ez8cUJnK6TXJiu5eV4X1yqxdr6noX55D24mU+AwHVFaG/nuJqkWrWE9vPxAKLVxUqQaXXxS2MxjTOQAsL3K9CBWtLwC8SQHn03Xx4T06SKKXIjMWvuzVisy3eb+BfuKLnWIglyJJICoCdC6j6i4qa0EAAYKsgnuMgWxxQD9qIFdFZBYY/VpFWDOFvA1m79xM09WtDjHN3Xp6Oxe2Kn5YvK94FdboQOBUbLOa5n4OxopXOrRpsWmqhdBIZR4H7nc41l18G/FxtNMxmU+mLZfySCAqAhZTU6ICQGVJQAjgavCS+PcgsvaUyycgc00MODK91l2C3atBqbuQF3enXBwKHY++5VT3in2F43BjiLilophe1eX3tyL66qVehcruy+4mPYL6ssI/U34CMoNnbfTLrPxVWLITARyD8sjS2E77Km6biv45saKMXNVhgwSkG+YqnHah52HeuuD+uEcz0U8SmD+AvKKyfvJmnTVg9wvKcimOBKIjwDvo0XUZFbYgkA0IxxrIlgHMYhqYiqqw+2EI+k8VYc0Usj+cFV7cqNj3OA5vhQi5UGSVzkIbL1kJh1y5e87gvDhguUlwcPFqrNGBgMUsFLkrb/ZawnYbcB4dje8MzudBOQrnK5fBedZnB+O/dnAuoo+F3QzOhQRT4wkwQG/8IUAAbQR+gM8W0wS/AOfD87OpsiCLzB5gKk5gCVSZULwaa3QgYBFgtJr5Q+uD0X9Oby8Pls+hl2fXXvM0fHmtfYPC54sQMMldzRCJv6F5lO/DP4tH7lT6MPNlvqAibLAQ8b3EB2MiARIAAQboPAxIICMAR+Qf+GgxlW9NyD3UK2jYLdN/LQZcryZr68XnaHWIWgXR1qu3vw3mb62DoJFS1oPTv20jLVc0Ogukz1MUKaLk2fZQSRZZZBoY+Dz68lXHIMSXEZ9GO52Y+WDacimPBKIkwAA9ym6j0oYELF65Jup+EU6oxYIqWijkwsQ1WsIaJmcX9K08y89UgQCcs9tR/W8VRHSraj29fSoa5nou3ejn286LXPk49SuleZHrDTQmd+XNE86fcoFrLfOG/DdwBc6DJ3lVM/Nhvmikn5XvZaQuxZKALQEG6LZ8KT0yAhgc5VnYCwzUlrts/2IgV0Uk7BZn7FPI8p+pGAE5j04rVoWluxCwmOauGbR0UptTcztRKbZtIpz/EcWqsHQHAqdjm9bd16sxLjzaoQ2LTVMshEYmU8beTzvXWXwY8WW00wWZ76Utl/JIIFoCDNCj7ToqbkhAnsm2SPIs+kgLwRoyMUDKHfTfachqoAzeAdTpdO27RzK9/Swd1YZLwe/5Hdi66fA93FKQwPIov2/BOiw+hADO4c9j07lDNpf9+qeyFYvUw29I/NCJReokWvbX6L/rvNqW+S5Wj8JZ+VxecVIvEuhLgAF6X0Qs0DQCGCTPh823Gdi9MmR+zECupsjPQdiLmgIbIuvdcGBkFWKmCgTw27sD1SVrJZne/rKWsA5yeOevA5SSm3iRqyS4IdW0ZoyEev58J+i/6hAbmvb1WRgsY6/nJL6L+DDa6bbM59KWS3kkEDUBBuhRdx+VNyRg9TzU5xDIyTvXXSYMlA9Bsa+6VM6/UgwwdPpIK8AQbTRldbJuUqeN3FaKwJ44Ny5bqiYrtRM4A19ead9Q4vPtGAv+XqJemSp8RARr1ID342XghaiT+SyfNWrLytcyUpdiSSAMAQboYTizlfgIyKJp8o5w7SRTOT+hLVRZ3g8g71ZlmU0QNxWODN+FXb2ntaa5W6/e/m6YKplJh8AiECML7jFVIIBA7wVUP6eCCKkaanq7rDuwf0VdY69+PQw41rkR4rOsYKCj+FgWb84xUJUiSSAsAQboYXmztUgIwMl5DaoeY6Tu4QjkljGSXVksbJ8NIbIYDBeMK0ZzFRTfrVgVlh5KAMffX7FN4xET69XbeedvaOdV/85ZKNUZioSqM0eCBOjQcw9kuWjd1DQXhn8E5zz57zJlvsrhRsodk/laRuIplgTiJcAAPd6+o+b2BP4XTVhMO5Pg/NP26pdvAYPm1ah9XHkJja05o7GW6xpeNcAQbTRk9LKK09t70Sm3b0sEBOuUq8pabQTOwGeZQVIm3Y/z/01lKpao0/Q1HH4C1nIH3XMSX8XihoL4VuJjMZEACXQgwAC9AxRuIgEhgIHzJfz7DyMan4Qj6v3OwRdg+xNG9qcqdjz61e0aAxFBrzrN3Xp6+xZguW5EPGNS9eCYlPWoazZ2nV1St1NL1itUDefJRVFhXKFKaRWWAPUIzyZlPsonjXT8j+w4NRJPsSQQNwEG6HH3H7W3J/BjNGHxLLoEcVaLrqhQweD5tHcdVQzVFTIS4vjKoIpMcezdCRG3VBDD6e0V4NVctel3VbXwl51BEmp6u7xWr8kXMz+D89yzWp1tJEd8FIs+Ep9KfCsmEiCBLgQYoHcBw80kIAQwgL6Cf0cZ0fgYrlCvZCRbRSzs/z8IukxFWHOE8Dlanb4uG2BI61Xq9tQev9kFUOCAnoW4swqBdcB4hyoCWPdNAmfi78sFWTyJ8lcUrFO2eJPXcLgQY+vxZcGFqJf5JvJqNYt0VOZbWcimTBJIggAD9CS6kUYYE/gZ5D9g0MbikPklA7naImXBuFe1hSYsbwycmzUSti+UaWWnuUtQUnZ6bx7btkeht+cpyDKlCfAiV2l08yoiAJLfwVkFxZyBenMK1ilcHOdHuSs7tnDFNCrIo3OHRWCK+Cbio2gn8aXEp2IiARLoQYABeg843EUCQgAOi6zo/k0jGh+Bs7KBkWwVsbD/rxB0pIqwZgiRO6zTm2GqnZU47u6G9DKLVZ2NuuIEW6Um3/mzYjpU7gE4Ly48dCO/FyZQdCZJqOntE2CJvFaviekLOD/N8mx45pN8xEjHb8J+8amYSIAEehBggN4DDneRQBuBX+LzvW3ftT4uBEFHawkzlPMdyPa+2qyh+YVF8w5gYWQdKxQNMERI2TvvHRVo3wjHVcbMpr+3uR2J1edlIXg/K+ENkit30PNerJJyFwRi09R1BuTxgR8FYlylGfFJxDfRTuJDiS/FRAIk0IcAA/Q+gLibBIQArvjOxr+vG9HYA47/3kayVcTCfpn2eDAyr3znI7oB+nTzfEVZqgeBosF2mWm9PZoftmtXbFll2FZusCDAi1wVqeK8LW8zkFeu5UnnoLysuWKacF6Ut5fsYtqIT+HC9oNg/IZP9eZplfki8n56i/Q12C++FBMJkEAfAgzQ+wDibhJoI3ACPsvq0hbpexgYR1gI1pKJgfUOyLK6SKGlpic5DDAq9gaOuXsg4oYCYji9vQAs50XlwqX3V1E6R/imenlnoQR5vRo0OhDZ4u6s9774Ks5nd3lWMvNBvmeko/hOvzGSTbEkkBwBBujJdSkNsiKAwVXuIh9pJH89yLVaMVVT5f+EsBs1BSYsawocniY6otpdmjfAkHaL3nHPrWvmvI7PXYEFqxKQC5bTqgph/YFzwODFPhxex/6z+pTR2t3ENRzk8bDvagE0lCM+iPgiFunIzIeykE2ZJJAcAVnMiIkESCAnATjpclFL3s+8Uc4qRYrJO1HXxSD2ZJFKocuCwbvRpjgcXMSpP/xx6E953RFTSQI43tZC1TzrP8j09pXAW56lVU/QQ97bfJq6YArsReB69Od7exXgvv4EcOzKncupPUqeD85W05rfahZ6vA1fHkBu0s0heQPK5uB7+1sgHH5A36wAte5GXsZAPbF9EzCYayCbIkkgSQJNOkkm2YE0KiyBbID5qlGrMjB+w0i2mlgwuA3CvqkmMG1BM9I2z946HG/3oZXrcrTE6e05IEVWZHMEDlZ39CJDUUndfrNQQq3ePhlWNM3v/CzOYa6D8+zIEt/DIjgX8TK9n8F5Bpr/SCAPgaadKPMwYRkS6EdAnJmb+hUquf8wOKQbl6wbstq30ViRZ4ND6uaprXHoz6U9KRSpLv0CDDHLcnr7opA/LlJ2sat9cOwGOND/XOjwfBc9ZNGyUDNDmrZ6u7xX/odduLvZnPkchxkpJL6S+ExMJEACBQgwQC8Ai0VJQAhgwBWH5itGNBaE3KONZKuJBQNZiVWmTJpMJ1ZTtH5BEthNql+N6DXoF3xbr94u09uXiJ5inAbIWg58HK9C3+F8LdOsT+8i4lrsf6TLPrXN6MO1IWxzNYH+BT0MFT/gX803NRSfQ3wPi/SVzGeykE2ZJJAsAQboyXYtDbMkgAHnTMifadTGznBm9jeSrSYWDGRF2k+oCUxXEKe5V+xbHGv3Q8S1PcRwensPOJHvGgX9x0Rugwf1u81CCXV3s9cz8B74aOog07nfh/OW6/VkxODM19hZ0/g2WTMzX6ltEz+SAAnkIcAAPQ8lliGBzgQ+ic1Wz1X9NwbORTo362crBt+fQ5tT/GjkUpPt0JejXGoWl1LdAgyxot8d9tKWou/kzvmepQWwogYBvrKwOsXzIOK5DmJCBejyerWmpP/E2Hixd2MzH+M7RnqKbyQ+EhMJkEAJAgzQS0BjFRIQAhiAb8G/44xorA25sQxuH4Ku/zDikIJYmZ7LAKN6T54MEfJ4ydBkPb19AhpcbGij/B6UwAQEE/K4CFNJAhivXkPVoc+a/wXbZeVu04S+kzd/SG5Ckpk+X4nEUPEx1jHS9bjMRzIST7EkkDYBBuhp9y+tsyfwJTTR6a6ERstHwLFZTUOQpQwMwk9DvgSgcsWcqTOB6Z03c2teAjjOHkDZazqUt57e3rSFrTogrn3T0tBg/9q1iF+BobNQQt09b8q7z2Uhvik4V8kaLa5T5lscYaSk+ETiGzGRAAmUJMAAvSQ4ViMBIYCB+An8+7oRjSUh90dGslXFgsMlEGg1VU5V15qErQeHaKua2k6p2aEBhthmOb19WcjfJSWAEdvCWSjVO+8CiHi2TUyoAL0p09v/BWPhfW18PX8U30J8DIv09cw3spBNmSTQCAIM0BvRzTTSmIC8RkUWTLNI+yGwm2gh2EDmlyHzBgO5qYhkgFG9J4dOc7ee3i6BxYjqalOCAoHdcC5cUUFOY0UgaJJp7qdmAB7Ed/PzNfpsC7T3jgZA/xV4nhiDnZlPsZ+RruILuX+1nJHtFEsCagQYoKuhpKCmEsCg/DpsP9zQ/h9iQF3GUL6K6IyDTGXs9r5dlXYiFjIZ/chgr0IH4hh7CNWvahNhPb29KVNz25C6/bgQNOOjItW7pzULJdTd8yY8IiLP8f9b9a6xl5D5EpYB9OGZL2BvDFsggYQJMEBPuHNpWjgCGJDktWvnG7W4CuT+t5FsVbHg8HcIPFhVaDrClod2Jb9iAABAAElEQVQpe6djTm2WtAIMUcByevvKkL99bVay4U4EZnTayG2FCFyI0rJuSOtOeqHKRQojGJQFMicVqRNhWZmVcBDGvhcj0V18CfEpLNL5mS9kIZsySaBRBBigN6q7aawxgU9B/myjNj4IZ2eMkWxVsRig5c7Md1WFpiOM09yr92Vrmrv19Ha5e75gdXUpQZHAaJwHN1CU1zhROD/LjK/jkC8LYPyOaONtAdqps4l/B9Mb61Qgb9v47eyEsh/MW75gOfF9xAdiIgESUCDAAF0BIkWQgBDAIP0X/PuxIY2fYYCN5VVDXwCHKwxZxCp6H/ShLDzGVJIAfmcPo6ocW5zeXpJh5NUOjlx/D+p/Db+jOQEUkYtcKadzYdzRMRiY+Q4/NdT1x5kPZNgERZNAcwgwQG9OX9PSMASORDMyfdAivQNCj7QQrC0TA7VcTZ+M/Li27MjlLZxxidyM2tWXae6W09vXgPwta7eSCnQiMAXBhkydZipJAOdnmX1imtBHC6GBA0wbqVf4Y2j+/WD5Rr1q5G79SJQUH8Iiic9zpIVgyiSBphJggN7UnqfdJgQwWMtA9VUT4fOEHg7HZ7ShfDXRYCF3OmWBoBB3atT0DiCIz9FWhyzB+VnVxXSVMBV7GAR2xVPrDrl4wlff1doFuRrfDaVWyFUyvkLymMAkjHFRXIDOfAbLhWy/mvk+8fUkNSYBpwQYoDvtGKoVNYGfQHuZ7m6R5K7EcRhwo3g2FoP2xdD3KxYgIpa5NfpvnYj1r111HFePIb9kqEjqU3MN0QUR/b4grbCRKgRSXr39Izj/XF4FTqi6ma8gaw6I72CRxNcRn4eJBEhAkQADdEWYFEUCQgADt/ViKZuhmZgWY/k29LW82ynYY0u8i+60x+DQrgvVopil4hRhCLX2Rz+NDNEQ2yhOAH0ja6WML14zihrHYIz/eRSazlNSfAXxGazSpzKfx0o+5ZJAIwkwQG9kt9NoawIYsOSVa78zbOdrcILWNpSvJhos5Bm9ach/UxMav6Dp8ZuQrAUyvZ3JN4Elod4E3yo2Wjt5neRSCRI4DzZ9Jha7Mh/ha4b6/i7zdQyboGgSaCYBBujN7HdaHYbAJ9CM1YJxcvfo2DBmVG8Fg/hzkLIv8jPVpSUhYW04T9smYUl6RhyYnklJWsRZKH67NcVHRO4E7skYy2JaU0V8BKuZJuLbiI/DRAIkYECAAboBVIokASGAgVwWkPm0IY1dEeR9yFC+qmjwuBsCJfiJycFRZTBEGAOMIUDq/orf0ybQYcO69WD7uQjsjP5aJVdJFgpGAH2yBBqTO+gpJbmwPC670ByFXZlvsKuhsjK1XXwcJhIgAQMCDNANoFIkCbQIYAD7P3y+oPXd4P/RGIjXM5BrIhI8LoRgy4sWJnobCT0QfbeIkWyKLUcgxTt/5Uj4ryULZfJREX/9tB9UWsyfWqU1kjVlDsTYJReYo0iZT3C0obIXgMevDeVTNAk0ngAD9MYfAgQQgMCH0cbLRu3I9LXfYkAeYSRfXSwG9h9A6HHqguMTuAxUHhef2klrPClp69Izblp6JkVv0ZToLRhswCezC8uDtzr9lvkCv4V64htYJPFlxKdhIgESMCTAAN0QLkWTgBDA4H4f/n3ZkIas0PoNQ/kWov8VQqN4TY2F8W0y39f2mR9rJADHdis0v06NKrDp4gRGo9/ksQQmBwTQF8tCDXn/eSrpJxi/fxSZMeILWK7a/uXMp4kMC9UlgbgIMECPq7+obbwEvg/VrzdU/7NwjsYYylcVjQH+dQg8APl+VcHxCdsL/bZCfGonqTGnt8fZrbzI5affZAZKNLO5+mCbif3/1qeMq92ZD/BZQ6XEhxFfhokESMCYAAN0Y8AUTwJCAAHpHPw7FFmeZ7NI8ls+PruDYSFfXSaYPAGh+yDLCu9NTeLMMjCsuffxu1kAKkysWQ02X47AFPQffZly7LRrpXIuuwdgJmKMshqvtbkPZGP/8RBs9VsQFodmvoy6/hRIAiQwmIDVD3lwK/xGAiQgQfotwPAdQxSrQ3Y0r14TDmByO/7tj/yafG9o4h3A+jt+R6jwtvrVoAYlCKyGOilNqy6BoP4qCBBXgRbyO4o9PQ8D9sXY9FRkhsjYLz6AVfpO5sNYyadcEiCBNgIM0Ntg8CMJBCDwdbRhuRrsJDhKBwewQ60JDPqXQNghyG+oCY1L0Bbos/XjUjk5bVO585dcx+Q0iK8szAnKsNhkyI7dp5wLG6ZgTPqLISd10dmYb7nApfgs4rswkQAJBCIQ+8k0ECY2QwI6BDDwvwJJhyFbBqM/xIAd1WJX4CKrzn5Bh3KUUngXvaZuw29lITQ9oabm2awOgfHoR3n/NlN9BFJYvf2zGIvOrg9h8Zazsf6HxWvmriG+ymGZ75K7EguSAAlUI8AAvRo/1iaBwgQw0F2KSscVrpi/gjiqv8kCj/y1ai4JLv8FFWJbMVeL2nT0lzwHzRSewK5ocsXwzbJFRQKLQ5YsOslUAwGcu0ah2S1raFqzyf/CGPQ9TYHWsrIx/jdox/Li1HGZz2JtDuWTAAm0EWCA3gaDH0kgIIHPoa1HDNsTZ+krhvKtRH8cgk+zEu5Y7prQbQfH+qWsGqe3p9G7M9IwI0orYr97Lq9T+3yE5GWMt7wwIj6K5arwESKnyiQQhgDv2IThzFZIYBgBXP0ej42nDtuht0FWjh8Dx+MKPZH2ksBlMbRyMfJW9q25auEX6KsPutIocWVwrC0MEx9DXiZxU5tg3lwYuQZ+Qw83wVhPNuJ3JAugbuxJpwK6yB3oGThu5PiJJoH5dlB2JvKChkqPB5fTDeVTNAmQQBcCvIPeBQw3k4A1AQx8cqf4p4btyMB9AgbyZQ3bUBcNLv+E0HHIf1UX7lvgRPSVXJxgCkdgLJpicB6Ot2VL4s9wLQdLwh1k45y1ATbHGpxL8HlwhMH5ctD7BGTL4PynDM5BmIkEaiLAAL0m8GyWBDICn8L/Ow1pyNTp38KJiuq3DsfgSegtzwbfZ8jGm+iloJDMqmAKR4DT28OxDtHS9BCNsI1BBGKd3i6ztA7EWDN7kDXOv2Rjudz1l7HdKolPIr4JEwmQQE0EonLaa2LEZknAjACcg5chfBry62aNDAzsCdlfM5RvIhpsZKrqLshNmrLKO4AmR9NwoXB0R2LrPsP3cEvEBDZCv24asf4xqj45QqWvgc4yffvVCHWXsVzGdKskvsi0zDexaoNySYAE+hBggN4HEHeTgDUBDIQ3oI0vG7dzBBxXmTYeVQIbuYMud9LljnoT0u7op5WaYKgDG/eFDrL6N1NaBGakZY5fa3Cu2gzaredXw46a3YqtYzG2vNhxr+ON2Rh+hLGKX858EuNmKJ4ESKAXAQbovehwHwmEI/AdNDXTsDlZEPJ4DPDvMGzDRDScBXkWfQ/k50wa8CV0Iagz1ZdKyWrD6e1pdu1knOcsn81Nk1o5q2Kb3n43zNwdY8oz5cytr1Y2dh8PDSwXd54J+eKLMJEACdRMwPKHXrNpbJ4E4iKAAXh1aCxX9y0Xdbsd8reCg/JSXHQGBsBnW+h8PrJMTU453Yj+kTtTTEYEcCzJ8/6PIy9i1ATF1ktgb/yGzq5XhbRbx29I/Mf7kdeIxNIHoed2OC4eiETft9QEa5npI9PyN3pro/4HuWixMfg8pC+aEkmABIoS4B30osRYngSMCGQD44eNxLfEygB/XOtLTP/B50rouz/yazHpXULXTeGQvatEPVbJT2ACijI4z88rtpKc5m7fY9uhiViCc7kYt2uMwXnWjTJmWwbn0syHGZxntPmPBBwQYIDuoBOoAgm0CGCAPAmff9X6bvT/IASAnzSSbSoWfOQO+iTk1IN0LhZneiQNxDY115ZGetL3xTluyfTMcmVRLI+IPAtqMq39Llf0ciqTjdXWrH+V+R45tWIxEiABawKc4m5NmPJJoCABDMhLoMrNyOsUrFqk+GwU3gWD8mVFKnkpC0b7QJeTkVO9CyrTDNdE/8z1wjwVPXDsLA9bHkWW5/2Z0iXwQfx+fpGuefVZht+QPOMvb9fwvqClPMold85lenh0CZx3gNIXIVueq+6B/NFgFN2iedF1KBUmgQIEeAe9ACwWJYEQBLKBchrakiDaKsmA/wc4AKtZNWApF4zOhHyZ7h7ja3LyoFkdhXbKU5BlChM4EDUsHd7CCrGCCQFOczfB+qbQXfDXe3D+T+gor1KLNTiXsfkPyJbnKvEx5JVqDM4BgokEPBFggO6pN6gLCWQEMGBei49fNwayMuSfjCB9hHE7JuLB6BwIHo/8ikkD9QvlNHebPrCeLmqjNaUWJbADzm1rFK3E8rkIeH9E5HlYsSfGCLn7HF3KxmSZISZjtGX6euZrWLZB2SRAAiUIMEAvAY1VSCAQgaPQjiyMZpm2hvBjLBuwlA3n4jzIl/dZy92S1NIBcNRSX7E+aJ+B56pocLugjbKxugjII3y8i65MH7+hhSFyP2WxmuKehLCdMDZcpik0sCwZk2VstkziW4iPwUQCJOCQAAN0h51ClUhACMDBmIN/05Gt39n6r3C6DpU2Y0zgdAH0lmfSX45R/x46L4F9Mo2fSY+A3D3nuKfH07skeVSISZfAWIhbRlekmrSHIGl7jAk3qkkMLCgbi//VuFnxKWRqu/gYTCRAAg4J0FFx2ClUiQRaBDCAzsLnqchzW9uM/v8YjsFuRrLNxYLTxWhkb+To3u/eBw7vAPYBVHA3p7cXBBZ58Q1wXntv5DZ4U9/rb+hugJL3nP/NG7C8+mRj8I/zli9ZTnyJqeAk77BnIgEScEqAAbrTjqFaJNAigIH0XHw+svXd6L8sRCPPo7/bSL65WHCaiUbkIoP1jANzW9oa2AV9ItOymSoSAMdRELFFRTGsHh8BXuRS6jP8hhaHqHFK4jTF3Aphcuc82qAzG3vluXMZiy3TkZlPYdkGZZMACVQkwAC9IkBWJ4FABL6Jds4wbmspyD8r5oAQjsfVsGEH5IeNWYUSL68z4jRdHdpTdMRQSmQEJuOcZh30RIaktLqy3oe3dTGugk474tz/WGmraq6YjblnQQ0Zgy2T+BDiSzCRAAk4J8AA3XkHUT0SEAJwPt7Av/ch/12+G6Y1IFuCdLlTEmUCq9uh+LbI1qxC8ZF+Z6pOwOvU3OqWUUIvAiti5169CnBfbgLeLnKdD813xzn/2dwWOCuYjbUSnMvYa5lkPHxf5ktYtkPZJEACCgQYoCtApAgSCEEAA+tzaGcCsvViaO9BG7+H4yB3b6NMYDULim+HfHOUBgxWemP0xSaDN/FbEQLgtz7Kb1ykDssmRYDT3Ct2J35DsjDcHhXFaFY/BcLG4Vz/kqbQkLKyMfb3aFPGXMskPsOEzIewbIeySYAElAgwQFcCSTEkEIIABtjb0M6hAdqSBdd+EKAdsybASqY8jkG+3KyRcIJ5F70aa1lokam5BPZBMLR0c81XsfwASFlYRVJ1Ib+AiMk4x79WXVStEmSMlbHWOh2a+Q7W7VA+CZCAEgEG6EogKYYEQhHAQHsi2jomQHvy+rXDA7Rj1gRYyawDuetzplkjYQRPze62hGktvVYOTM8kWlSAwKIoO7lAeRYdTsDLIyJHQzUJOOcMVzGeLdnYav06NQFyTOYzxAOHmpIACQwsQAYkQALxEcDgLoseXYy8vbH2cyF/Egb4Pxq3Yyo+4/VTNHKIaUO2wvdEP5xn20R60tH3Mn30xvQso0UFCVyB34/1+bKgSnEUx29oZWj6D+S6H3v6CvrwG3FQ664leMqjaichW98kk9ljO4PZ7O7acA8JkIBHAtYnB482UycSiJ5ANuBOgiHWq5XLOeIEOBRbxgxNeCF/ADZ8CVkW3IsxcZp7uV7zcuevnPaspUVgW5zHRmkJa5gcGWvqDM7lQvHHcQ5PITiXsfQEZGv/W3wDubjO4BwgmEggNgLWJ4jYeFBfEoiGAAZeecZaHKfXjZVeDPJPh3O7lnE75uLB7FtoRF5b9qp5Y/oN7I8+WEJfbPISOb09+S7OZaDMGJyRqyQLDSVQ5+rtL0CZ/XDu/uFQpWL7no2hp0NvGVMtk/gEEpyLj8BEAiQQIQEG6BF2GlUmgRYBDMBX4fOnWt8N/68E2WfDwVjOsI0gosFMnuHfFfmpIA3qNSLvH5aFmphyEsDxug2KjspZnMXSJyAX55gKEMBv6O0ovnWBKppF75W2cc4+Q1NoHbKysfMctC1jqXX6VOYbWLdD+SRAAkYEGKAbgaVYEghFAAPxj9DW8QHaeyfaOA+OxlIB2jJtAsyuQANbId9t2pC+cN4BLMaU09uL8Uq99Ho4f8nvnik/AfkNyeyD0OkSNLgFztV3hG5Yu71szJT1Q9bXlt1B3q8zn6DDLm4iARKIhQAD9Fh6inqSQG8CH8Luq3sXUdm7OaScBYdD7uZGneDE/B0GyJ0hWUgnljQG7FePRdk69QQnGd8m1qkD23ZJgBe5inVLHRe5/hcq7o5zdGyznIaRzcbKs7BDxk7rJD7Ah60boXwSIAF7AgzQ7RmzBRIwJwBH5hU0Mh75HvPGBga2QxunwvFYJEBbpk1kDuBuaOQ3pg3pCZdzNqfp5uM5BsVWzVeUpRpEYDLOXSMaZG9pU8FpfVSWtyCESvLs9L/gvPxR5OgXN8vGyFNhk4yZ1knG/vGZL2DdFuWTAAkYE2CAbgyY4kkgFAEMzE+grbHITwdoU4LaP8ABkde9RZ3A7VXk6TDiM8hzIjCGdwDzdVIdd/7yacZSdRKQdTT2qVOBiNoO+Rt6Elx2w7n42Ij4dFU1Gxv/IDZ1LaS3Q8b8sZkPoCeVkkiABGojwAC9NvRsmAT0CWCAvgtS90N+VV/6MIn7YsvxcESSOI+A3Xdhz57IIS5wDINZYMOGYL5pgfKNK5o5xxMaZzgNzkuAryzMRypUgH4b1JHnzS/Np5bvUtmYKOvCyBhpnWSsl1XuZexnIgESSIRAEo51In1BM0hAhQAGanmm+hDkEO/7Fgfup3BI6lhESIVXuxCwuxDf5VnBW9u3O/zMu+i9O2V37F6+dxHubTCBsThnLdtg+/uaDj6jUUgWBrVOp6GBbXDuvc+6oRDys7Hwp2grxMUNGeMPycb8EOaxDRIggUAEGKAHAs1mSCAkAQzYJ6K9LwVq84No55hAbZk3kzmK8noumZ7oNU2BIxj94wWGcEM4x4bqU7QxAVk/g8dIb8hTeu9W2fstSNkf59wXVaT5ECJjoYyJIdKXsrE+RFtsgwRIICCBJO56BeTFpkggKgII4o6DwqGchaPgLBwRFaA+yoLfF1BEnEiPFzP3AW9ZHZipjQD6TIKvx5GXatvMjyQwlMDV+P3IhTimIQTwGxLfUO5orzlkl9bXf0LQIeD/ey2BHuSA21HQ498D6fJz8Ds0UFtshgRIIDABj05nYARsjgSSJvAvsO6CQBZ+EQ5KKOckiElwgP4DDe2N7PG5dD5H2/kokP5icN6ZDbfOJ7A1zlfrzP/KT20EtsZnq+D8IcjeLsHg/IuwK9T4J2O6jO1MJEACiRJggJ5ox9IsEhACcIJm499EZFmEJ0Q6Ck7vx0M0FKoNMDwXbcnzmFeHajNnO+PBmoHocFicujycCbd0JsC1HDpzsfoNnYfmNsc59cbOzca5NRvzZKZViCRj+cRsbA/RHtsgARKogQAD9Bqgs0kSCEkAA/nzaE/uKj4SqN1j4LAcFqitIM2A4YNoaAfk7yDLwjwe0qJQYpIHRbzogONucegixzoTCeQhMC1PoSaVwW9I/ELt88prkHk48l44lz6WEs9srAu1BouM4XtnY3pKGGkLCZDAEAIM0IcA4VcSSJFAFmBK4BJiMR55fvFYOC6p3UmfDY6fg23jkJ9C9pA4zX1wL4zH15GDN/EbCXQlsA7OU9t13dvMHTvB7FUUTf8bZG2Jc+f3kL1c3FQxLxvjjoWwEOs5ydgtwblcLGYiARJInAAD9MQ7mOaRQIsABvab8FmmLs5pbTP8Lw7L9+HAhHomz9CUwaLBURZmkynvVw7eU8u3HcDY6lnRWgyq2KjV1NyKarG6YwK8yDW4c6YM/lrpmyxSuhnOmTdXkuKwcja2fR+qhQjOZcw+KBvDHdKgSiRAAtoEGKBrE6U8EnBMIAsuPwQVQ93JkGfSZWXbpBI4ykJHY5D/EzkUSzQ1LIlzOH3Y1gZuwHG2DMzeo4Gm0+RqBCbh2Fmkmog0aoPDCFgyQcGaZyBDnpM+DPllBXmuRGRjWqhxTcaXD2VjtysOVIYESMCOAAN0O7aUTAIuCWCg/wUU+2RA5f4dDo3cTQ9xpyGYWeAoU96/gAbHIj8arOHhDfEO4DwmB+DfwsPxcAsJ9CSwLPbKYytMAwN7AoLwqJIuQ+WNcW48pYoQj3VlDJOxDLqFnBn2yWzM9oiEOpEACRgRYIBuBJZiScAzAQz4P4B+8lqYUEmeR/8ZnJvkzjlgeS5sezfyH0PBHNLO+uC6xZBtTfzK6e1N7HUdm3mRax7HKr8heWPIl5F3wjlRZhgllbKx62cwKuTaKl/MxuqkWNIYEiCB/gSSuqPV31yWIAESaCcAp0NeDRMyUP8d2nsfnA5x5pJL4HkwjJI7LEsFNu5HYPqxwG26aQ7cV4QyssLxgm6UoiIxEXgdyq6K35CXxR+Ds8NvSBZXlBXWlyjR+H2oMxX8rilR130VsFkISh6PXOUCRlE7jwLPI4pWYnkSIIE0CCR3NyuNbqEVJBCGQOYAyN30UEkcnFPg8CT5zCd4/gr2bYIs0zxDpslgKs+PNjUdCMMZnDe196vbLb8dzcXRqmsUXsI+aLJMcP5b1BudcHAuY5VM1w8ZnP+AwTmIM5FAgwkwQG9w59N0EsgIyPPoPw9IY1+0dUZ2xyZgs2GagmM1Cy3thPx5ZHn/b4i0AhrZK0RDTtsI6Tw7RUC1KhJo+jT3ohcoXgDvGTjfTUN+viJ7l9WzMeoMKCdjVqgkY3HINWJC2cV2SIAEChDgFPcCsFiUBFIlAEdELtadgFzUSauC5ApUlve6JuncCRhwlbvpMjVSnlG3TqeA5UTrRrzJB+PVodMDyBzPvHVOfPqsj9/QXfGpXU1j/IaWhgSZ3p53ZtNVKCvB+T3VWvZbG0zkMSV5peZ2AbU8EW1NB9e5AdtkUyRAAg4J8A66w06hSiQQmkDmEMxAu6cFbFscn4vgCC0XsM2gTYHrLWhwc+SvIVvfTd8HLJcNaqCPxiZDDQbnPvoidi3kHNjEtD+MzhOcv4Rycnd3+8SDcxmTLkIOGZzL2CsXPRicAwQTCTSdAAP0ph8BtJ8EMgJwDGbjowQ7FwSEIsHrlQgs1wrYZtCmwPU15CPR6KbI1xo2Lg62PIvdtMTp7U3rcTt7p+Fc1MSLPXl+QzIubIRz2feRkw0is7HoStgqY1OoJGwng6uMwUwkQAIkMMAAnQcBCZDAWwTgILyKL/shX/7WRvsP70QT18Ax2tK+qfpaANs70Po2yJ9CljtRFqlRz9HimFkbEEM60hZ9Rpl+CIyCKjv4UcdeE/yGVkQru/Ro6Vns+wDOX7sjz+pRLvpd2RgkK9HLmBQqyVi7Xzb2hmqT7ZAACTgnwADdeQdRPRIITQCOwstoU1b0vS5g2yuhrUvgIE0I2GbwpsB2LvIxaHgjZIuZCtuCoQStTUkh10xoCtOm29moi1zo7InI8hqxTulP2LgBzlm/7LQzpW3Z2HMJbJKxKFSSMXafbMwN1SbbIQESiIAAA/QIOokqkkBoAnAYnkebeyLfGrDtxdDWSXCUPh2wzVqaAt9ZyLuj8UOQn1FWokkBRp6pucp4KS5xApNwDlo0cRvbzet0kesfKDAR56gJyI+2F07xczbmnATbZAwKlWRs3RN8ZaxlIgESIIFBBBigD8LBLyRAAi0CcByexuedkEPeSZdz0nfhMP0P8oItXVL9D8a/gm0ynVL+v4GskRoRoOP4eBdgyUwEJhLQJCCrd4/XFOhVFn5Dq0O39oXQ5Bno7yK/E+cmefd30knGGOT/gZFic0h/WMbUnbIxNmnGNI4ESKAcgZAnpHIashYJkEBtBDIHYlcoEPKZdLH3o8inwXlaXL6knMD4cWS5k74t8k0Ktq4DbvKse+qJd89T7+H67GvERS7gbX8DwmX4Phrnos8gv1gf+jAtZ2OLrJwuY03IJGPprmAsF8CZSIAESKAjAQboHbFwIwmQQIsAHAmZgifT3S2emW410+n/3th4GRypVTvtTG0bOF8Nm2TBM3EYq057b0KAIcEFEwlYENgD552QzyJb2JBHplzkkvefvw/nnx2RZSHL5FM2psgFCRljQiYZQzmtPSRxtkUCkRJggB5px1FtEghJAI6bLBw3DlnuOIRMm6Kxa+FQNWIqMzjLInL/C5vXQ/45ctlp75PBbGHUTzLBts1g2LpJGkejPBCQRdM6PZvtQTcVHfAbWguC5KLg+jjnnKAiNAIh2Vgir7uUsSVkkrFzXDaWhmyXbZEACURIgAF6hJ1GlUmgDgJwLF5Fu7Li74mB218D7cm70ncL3G5tzYH1k8iHQoGtkW8oociyqCMr8aeaOL091Z71Y1fqs1BkocqPIz/nB7mtJtkYciVakTElZJIxUxbdkzGUiQRIgAT6EmCA3hcRC5AACbQIwMGQRYSmI8vd3ZBJFm46Gw7WB0M2Wndb4C13erZAPhj5IeQiaUaRwrGUxTGwAHQ9MBZ9qWe0BDbDsbZBtNr3URznlrKzc/pI9rk7GzvOhnYyloRMMlZOz8bOkO2yLRIggYgJMECPuPOoOgnUQQCOxly0exjyDwK3L9NOj4OjJSu8jwjcdm3NCW/k/4MCMu39i8iyJkCeNBacls9TMLIyspje2yPTmerGSSDJi1xxdkU5rWWskDEDtY9DljEkZJIx8rBszAzZLtsiARKInAAD9Mg7kOqTQB0E4HC8gfwJtH1UDe3LImqXwularYa2a2sSvP+J/G0o8A7kHyHLbIZeSS5ipDgVPEWbevUj99VHYBrOMzJjgylCAtkYcSlUlzEjdDpKxkjkRs1UCA2Z7ZFAqgQYoKfas7SLBAIQgPNxBJqRu7qhkzybfSMcsB1CN1x3e2D+BPLHoMe7kE/to09Sz9GivxeEvbIOAhMJhCAgzyrvFKIhtqFLIBsbboRUGStCpy9mY2PodtkeCZBAIgQYoCfSkTSDBOoiAEdE7urK3fTQdwpWRpsXwRH7ZF2219kuuN+FvD902B75qi66bAk+MjU+lSTBkvQ7EwmEIpDURa5Q0OpsJxsTLoIOoc8VMgbKXXMZE5lIgARIoDQBBuil0bEiCZBAiwAcEnnW7lDkOa1tgf7LM4VHwyH7LfLigdp01QzYX4Esz2XvhfznDsqlFGBwenuHDuYmUwIH4Nwy0rQFClchIGOAjAUQdjRy6OfNZew7NBsLVeyhEBIggeYS4LNVze17Wk4C6gTgHO0Nob9DXkJdeH+Bt6PI/nCQ/t6/aLol0AfyerWvIW+aWTkL/9cGl9AzHLLmdf7BLnmm/jFkeYUcEwmEJDANvx8J/JicEsD5Qdbm+BPyRjWo+CLaPAjHyFk1tM0mSYAEEiTAO+gJdipNIoG6CGQOijwX/nANOohjdj0ctXE1tO2mSfTBmcibQSGZ/n4L8ijk7ZFjT3vAAAbnsfdinPqnNAslzh7ooXV2zr8eReoIzmWs24HBeY8O4i4SIIHCBBigF0bGCiRAAr0IwFG5Cfu3Qr6tVzmjfUtD7mlw2L6O3OjzG/pBFpB7D7Isqib/Y0+c3h57D8ar/244n6wSr/ppai7neDnXw7rTkOXcHzrJGLdVNuaFbpvtkQAJJEyAU9wT7lyaRgJ1EoDjtBTaPxl5t5r0OBftToXz9ExN7bNZJQI4lhaDKJnevqSSSIohgaIEDse55HtFK7G8DQGcE2Q2jTx2sKdNC32lXoASE3FMPN+3JAuQAAmQQEECjb7DVJAVi5MACRQgkDkuY1Hl5wWqaRYVx+0mOHLbaQqlrFoIyNoGDM5rQc9GMwKc5u7kUMjO6TJTq67gXMa0sQzOnRwQVIMEEiTAAD3BTqVJJOCFAByY2ciyuru8L72ORcrWRLsz4dDJlPfQq/p66YYU9OD09hR6MW4bRuMc8u64TYhbezmHy7kcVsxElnN76CRj2BEypsnYFrpxtkcCJNAcApzi3py+pqUkUCsBOFZToMAvkRepSZFr0a6sxnxPTe2z2RIEcNzInfPHkRctUZ1VSECTwHdw/vicpkDKykcA54F1UPI3yFvmq6Fe6lVIPAT9f6K6ZAokARIggSEEeAd9CBB+JQESsCGQOTbyPPrTNi30lSqO3c1w9A7uW5IFPBEYD2UYnHvqkebqMg3nD/pNgfs/O2ffjGbrCs5lzNqNwXngjmdzJNBgAhxoGtz5NJ0EQhOAg3M52twaua672Eug7V/C4fsDsiwyxOSfAKe3+++jpmi4GgzdpSnG1m2nnKPlXA09ZOaVnLvrSDJWbZ2NXXW0zzZJgAQaSIABegM7nSaTQJ0E4Ojchfa3Qr66Rj0moe1b4fyNqVEHNt2HAPpnORTZvU8x7iaBkATeF7KxpraVnZtvhf1yrq4ryRglr1GTMYuJBEiABIIRYIAeDDUbIgESaBGAw/MkPu+MfHxrWw3/V0ebF8ER/A/kETW0zyb7E5iAIuyb/pxYIhyBCThfLB6uuWa1JOdiOSfD6ouQ5RxdV5KxaedsrKpLB7ZLAiTQUAIM0Bva8TSbBOomAMfnFeQZ0ONjyK/XpI+cAz+PfDWcwvVr0oHNdicgCwsykYAnAhKcv9+TQqnokp2D5a61nJPr8k9lLPqYjE0yRqXClnaQAAnERYCruMfVX9SWBJIkAMdsGxh2ErI841lXehkNfwpO2U/rUoDtzieAY2JlfPsH8oLzt/ITCbgg8DC0eAfOFf90oU0CSuD3/iGYcTTyyBrNkX6dhH69qkYd2DQJkAAJ1HaFkuhJgARI4C0CmUO0GTZc/tbG8B/EMTwWjuIFyGuHb54tDiFwIL4zOB8ChV9dEJALiR91oUnkSsi5Vs65MONY5DqDcxl7NmNwHvkBRfVJIBECdU0hSgQfzSABEtAiAMfoUcjaGfn7WjJLytkV9W6D03g4MgPEkhAVqnH1dgWIFGFG4PM4PyxpJj1xwXJulXMszLwNWc65dSYZc+R5cxmDmEiABEigdgKc4l57F1ABEiCBoQTguMmzx8ch13lHRdS6AflQOG7yDl6mQATQ/29HU7OQOUYFYs5mchOQBS5PRT4Z+SKcG2bnrsmCbxLA73s0Psj5XWZN1ZnksSY5v59YpxJsmwRIgASGEuAd9KFE+J0ESKB2ApnDJK9i+3vNyogDeR0cym8jL1qzLk1qfjKMZXDepB73bevjUO8nyHKndxWcnw5DPg+ZwXmBfpNzqJxLUeU65LqDcxlb5BVqDM4L9CGLkgAJhCFABygMZ7ZCAiRQggCcuaVR7QTkfUpU164iDp045jO1BVPeYALod5m5sOngrfxGAkEJPILW/ogsd8ovw+9+btDWE2sMv+kxMOlnyO9wYNqZ0GE6+vQ5B7pQBRIgARIYRoAB+jAk3EACJOCJABw7OU99GfmryHXP+nkDOvwc+bNw7p7FfyZlAujvdSHyLmWxFEcCeQjcg0ISvElQfhWD8jzIepfB73kZlPgO8qG9SwbZKxdZvob8DfStnMuZSIAESMAlAQboLruFSpEACQwlAEdvL2z7DfKyQ/fV8F0WE5J35Z5SQ9tJN4l+3gIGfhN5e2Q+VpB0b9dunLwm7RLkc5HPwe+57kdqageiqQB+ywdA3v8gr6Ipt6SsZ1BvGvr4nJL1WY0ESIAEghFggB4MNRsiARKoSgAO3yjIkCnv21aVpVRfFov6KJw+eX8ukyIB9PViELcD8u7IeyC/C5mJBKoSuBMCJEiToPxS/HZfqSqQ9QcTwG9XXkP3I+T9Bu+p7duVaFmmtM+qTQM2TAIkQAIFCDBALwCLRUmABOonAOdPXn12BLJMe1+ofo0GXoAO30I+Bg7gqw70SVIF9PvbYJgE65J3Q14emYkE+hGQ54wvRW7dJZ/VrwL3lyOA3+giqPlJZDk/e3gFnSzi9w3kb+HcPAf/mUiABEggCgIM0KPoJipJAiQwlACcwS2xTaa8rzN0X03f70W7h8MRlLvqTIYE0PeyFsG7kWUafCuvatgkRcdDQB4/ubwt34rfpDx7zGRIAL9JuVv+XeS1DZspIvoeFJYp7dcWqcSyJEACJOCBAAN0D71AHUiABEoRgFO4BCrKM47vLyXAptLFEPspOIa32oin1E4EcCzIhZpWsC7/1+1UjtuSIyCB2GXIbwbl+N3xOfKAXYzf3cZo7mjknQM226+p/0MBWSPkxX4FuZ8ESIAEPBJggO6xV6gTCZBAIQJwEiehwrHIHhaQE93nIP8M+ctwEp+UDUxhCeCYWBktbov8XmR557Lk5ZCZ4iXwPFS/CflG5GuQL8fvS16HxhSYAH5fK6DJbyAfhrxg4Oa7NScLwX0Yx8RJ3QpwOwmQAAnEQIABegy9RB1JgAT6EoDDuAYK/Rp5TN/C4Qo8i6a+jvw/cBpfD9csW+pEAMfIWti+ObIE6/Jf3rXu5aIOVGFqIyAXtlrBuATkku/B74ivx2qDFPojfkMj0ObHkL+CvEzo9nu0NxP7ZuD4eLBHGe4iARIggSgIMECPopuoJAmQQB4CcB7/H8p9DlmCYnEkvSR5r/en4Tye5UUh6jGPAI6ZdfBpNPKGbXl9fJYFr5jsCchsk/uQ/4rcCshvwm/lAfum2UIRAvit7I3y30Ner0g947Jy4VMuFvwXjhmuNWAMm+JJgATCEGCAHoYzWyEBEghIAI6k3CH9LbInR1IInIcsz6dLMMLklACOH5myuzZye9Aun+W5dg+rU0ON6NIT0PjOLMsFq9ZnuSvO2SWOuxO/hw2g3tHIezhTU46jqTh+bnCmF9UhARIggUoEGKBXwsfKJEACXgnAqRwJ3Y5BlmckPSV59c+Pkb8Jx/JxT4pRl/4EcFzJc+wyVV7yqLbP8n1NZHl/exOTvM7sIeR/ZP/lsyzg9mYgjmNdHvdgiogAjvWVoO6XkD+C7OGVlu30foovcrHz5faN/EwCJEACKRBYIAUjaAMJkAAJdCMAJ3M89klAvGq3MjVtfwnt/hD5O3Ayn65JBzarSADHmoypKyOvhrxK9lm+S27/Lp/l2XfvY/Br0FEC62ey/4/hf3sQ/lYwjmNYjmemBAhkF6E+C1P+DXlxZybJooAfwfF2mjO9qA4JkAAJqBHw7hyoGUpBJEACzSUAh3MZWP8d5A8iezvvycrUcqf/e3A65S4kUwMI4JgcATPluFyqT5Yp9XJXXu5gSh3JnT637nDKdHEJrPP8l6C6PQBvBeLy/xkcj//Ef6aGEMAxuTRM/TTyJ5HluPSUZHHAnyN/FselHLNMJEACJEACJEACJEACsROAAzoG+S5kj+kZKHUEsrzbnYkESIAEghCQc0527pFzkMck5+wxQWCwERIgARIgARIgARIggbAE4Ogtivxt5NeRPaYnoNRnkeUZeiYSIAESMCEg55jsXCPnHI9JztFyrl7UBACFkgAJkAAJkAAJkAAJ+CEAp28T5OuQvaZHodgnkOmc+jlsqAkJRE9AzinZuUXOMV6TnJs3iR42DSABEiABEiABEiABEshPAA7ggsiHI7+E7DU9BMU+grxwfstYkgRIgAQGE5BzSHYukXOK1yTnYjkny6sOmUiABEiABEiABEiABJpIAM7g2sgXIHtOs6Dch5F5R72JByltJoGSBOSckZ075BziOZ0P5dYqaSarkQAJkAAJkAAJkAAJpEYAzuH7kZ9C9pweh3JfRV4xNf60hwRIQI+AnCOyc4WcMzwnOee+X89ySiIBEiABEiABEiABEkiGABzFlZBP9OzNZrq9jP8/QV4vGfg0hARIoDIBOSdk5wY5R3hPcq5dqbLRFEACJEACJEACJEACJJA2ATiNuyPf4d27hX5zkU9F3j7tHqF1JEACvQjIOSA7F8g5wXuSc+vuvezhPhIgARIgARIgARIgARIYRAAO5ELIH0P2Pu0dKr6ZrsXfSchcYGlQT/ILCaRJQH7r2W9efvsxJDmXyjl1oTR7hFaRAAmQAAmQAAmQAAmYE4AzuRzyD5G9vjsdqg1K9+Lbx5EXN4fDBkiABIITkN929huX33oMSc6dcg5dLjgsNkgCJEACJEACJEACJJAmATiXGyKfhxxLehqKHoW8Rpo9QqtIoFkE5Lec/abltx1LknPmhs3qKVpLAiRAAiRAAiRAAiQQjACczX2Q74zFO4aec5DPQt4PmVNLgx0pbIgEqhOQ32z225XfsPyWY0lyjtynOgFKIAESIAESIAESIAESIIE+BOB4jkD+NPKzyDGlR6Cs3FVfp4+J3E0CJFAjAfmNZr9V+c3GlOScKOfGETXiY9MkQAIkQAIkQAIkQAJNJAAndEXkY5FjurMFdd9c/f1C/D8IeZEm9h1tJgFvBOS3mP0m5bcZw2rsUPOtJOdAOReu6I0r9SEBEiABEiABEiABEmgYATilmyBfghxjehJKfw+Zz4k27LiluT4IyG8v+w3KbzHGdAmU3sQHTWpBAiRAAiRAAiRAAiRAAhkBOKnyfPqNyLGmK6D4wcgj2akkQAJ2BOQ3lv3WrsT/WJOc6/icud1hQskkQAINJLBAA22mySRAAiRgSgAOq5xbJyB/Dfldpo3ZCX8Ook9E/i3ylQsssMBcu6YomQSaQQDnhv8HS7dFnprlpSK1/A7o/VXkP+Lc8EakNlBtEiABEnBJgAG6y26hUiRAAikQyJzxybDlSOT1IrbpYeh+MvIf/n979xZjR13HAZxwKXJpUKsoCFjqBcQUUESkEGKicvHBJ0GjPPigJMYHEzUxMdEYY0xM0IQHfQASX9Bwe/JBipfEEApiRZEqtqilIIqiVSrXtoB+f80Zcrrsdre75+zO5TPJL3P27Mx//v/PnMme786cM6m7vCHv8J7U9WUXGP3DbkM2fEXqw6kTl70Tk9vgg2nqq6mb/NNucqhaIkCAwLiAgD6u4TEBAgSmIJA36Iel2StTX0mtm8ImlrPJR7OxW1IV1u8R1peT3ra6IjAK5eelvxXKL0+d1JW+z9HP7Xn+a6kbcsy/MMcyniZAgACBCQgI6BNA1AQBAgQWIpA37XXboU+kvpw6OdX16ZEMoIL6zXnTvrnrg9F/AksVyDF+btqoUF51ylLba8H6dYx/PfW9HOPPt6A/ukCAAIHeCwjovd/FBkiAQNsE8iZ+Vfp0VepLqRPa1r9F9uehrFdn1uvS118vsg2rEeicQI7nd6bT9VGWOlN+aucGMHuHH8vT30hdm+N5z+yLeJYAAQIEpiEgoE9DVZsECBBYgEDe2B+VxT6d+mLq+AWs0pVF/pyO1mfWf5Sqz6w789aVPaef8wrkuD08C21IfTBVnyl/U6ov0+MZyDdT381x+1xfBmUcBAgQ6JKAgN6lvaWvBAj0UiBv+I/JwD6T+mzqxJ4N8r8Zz89SG6vypr8umTUR6JRAjtG6XP3SUb0v865++/pc7vVFkNekvpNj9Om5FvI8AQIECExfQECfvrEtECBAYEECCQF16fvHUp9LrV/QSt1b6IF0eV9Yz/yOhIHd3RuCHvddIMfikRnjRakmlJ/R0zFvybi+nfpBjkWXsvd0JxsWAQLdEhDQu7W/9JYAgYEIJCBckqF+IfX+Hg/5mYzt56nm7PofezxWQ2u5QI65t6SLTSB/bx4f3fIuL6V7P83KVyeU376URqxLgAABApMXENAnb6pFAgQITEwgoeGsNPb51EdT9S3wfZ7qVk63pX6c2pTwsLPPgzW2lRXIsbUmPbggdXHqstS6VJ+nvRncjalv5dj6bZ8HamwECBDosoCA3uW9p+8ECAxGIGHiDRlsfUb9qtRxAxn4toxzU+quUW1NsPjfQMZumBMUyPFT73dOT20YVQXz01JDmHZlkNemrsnx89chDNgYCRAg0GUBAb3Le0/fCRAYnECCxuoM+pOpCutvHBjAvzPeu1MV2Cu4b07gqMvkTQT2E8hxUpen1z3JK4hXKD8/9erUkKaHM9j64rfrc5w8OaSBGysBAgS6LCCgd3nv6TsBAoMVSACpWz3VLZ7qc+rnDBSibt/2m1Rzhr0ui3eGcIAvhhwPdYVJE8YrkL8jVcfIEKd7M+irU7fmeHCLwyG+AoyZAIFOCwjond59Ok+AAIFDDkk4uTAOdel7Bfa6t/qQp79k8PeltozVNkGlHy+J0T+m6tL0ustBU2fn8cn9GOGiR/Fs1rw1dW1e63cuuhUrEiBAgMCKCwjoK74LdIAAAQKTEUh4eWVaujJVl8CfNZlWe9HKnoxia2o8tG9JkKkwb2qpQF7PFbqbEN7M63Pkq1ra5ZXoVn3Z2/WpG/J6fmIlOmCbBAgQIDBZAQF9sp5aI0CAQCsEEm7q87efStW3v69uRafa14kKNL9LjQf3Otv+z/Z1tb89ymv1tRndzLPiFciH8mWIB7tzn8wK9W3s1+W1uvlgV7Y8AQIECLRbQEBv9/7ROwIECCxJIOHn2DRQIb3C+ruX1NhwVq4vntsxqofHHu97LqHo8TxnWqBAXoPHZ9G1M6q+4LB5rs/3G88wJzb9Mi1dl7oxr8GnJtaqhggQIECgVQICeqt2h84QIEBgegIJSmem9QrqH0+9anpb6n3L9XnflwX3PPdIqs6+70w9kRDV61vC5fVU7yHqYxVrUnUW/JTU2hlVQXzo34sQgkVP/8ma30/V2fL7F92KFQkQIECgMwICemd2lY4SIEBgMgIJVq9IS/WFchXWL5pMq1qZIfBCfq5wVWH9QFW3jmt+vyuPdyeI7c182aa8Ho7Ixo5M1SXlFbar6pZkzeO55vVPnsNSpskL3JEm62x5fRP7c5NvXosECBAg0FYBAb2te0a/CBAgsAwCCWdvzmY+Mqr1y7BJm5hfoM681xfbjdfuBfxcLVfQri9Ra2q+n2s57wWC0IJpS/pwU1VC+Z9a0B9dIECAAIEVEPBHeQXQbZIAAQJtFEhYf1v6VWH9ilQ9NhEgMF2BP6T5m1MVyuuxiQABAgQGLiCgD/wFYPgECBCYTSBhvc6mV1Cveutsy3iOAIFFCTyYtSqU35xQXmfNTQQIECBA4CUBAf0lCg8IECBAYDaBhPWz83xzZn3dbMt4jgCBAwpsz2+bM+X3HXBJvyRAgACBQQsI6IPe/QZPgACBgxNIWH9X1qiwfnmqvqHbRIDA7AIP5+lbUnX5+q9mX8SzBAgQIEBgfwEBfX8PPxEgQIDAAgUS1t+TRT+UujRVZ9n9TQmCabAC9eV+dXZ8Y+qHCeW/GKyEgRMgQIDAogW8mVo0nRUJECBAoBFIWH99HldQvyz1gZT7rAfB1HuBupXeT1K3pTYmlP+99yM2QAIECBCYqoCAPlVejRMgQGB4AgnrdW/s81IV1iu0n5Py9yYIps4L1Fnye1N1lrxC+T0J5XXPexMBAgQIEJiIgDdME2HUCAECBAjMJZDAfnx+d0mqwnrN16RMBLoisDMdvT1Vofz2BPLHu9Jx/SRAgACB7gkI6N3bZ3pMgACBzgokrB+azp+bai6Hr7Prh3d2QDreR4HnM6g6S77vsvXMNyeUv9jHgRoTAQIECLRPQEBv3z7RIwIECAxGIIH96Ay2Loe/YFTnZ35cykRguQR2ZUN3pzaNqi5bf2a5Nm47BAgQIEBgXEBAH9fwmAABAgRWVGB0hv3t6cSFqSa0r13RTtl43wR2ZEBNGL8zj3/vDHnfdrHxECBAoLsCAnp3952eEyBAYBACCe0nZqBNWK953dLNZfGD2PtLHmRdrl63PmsC+aaE8b8tuVUNECBAgACBKQkI6FOC1SwBAgQITEdgxmXx9Rn29al1KX/TpkPelVbrG9a3p7ak6jPkFcpdrh4EEwECBAh0R8Cbme7sKz0lQIAAgTkEEtqPya8qqFedOap67H7sQejhVPcfryB+/6jq8ZacHX86cxMBAgQIEOisgIDe2V2n4wQIECAwn0CC+0lZpgL7eHA/LT8fMd+6ft8Kgb3pxbbUeBC/P0H80Vb0TicIECBAgMCEBQT0CYNqjgABAgTaLZDQvio9PD1Vwf2M1KmjWpv561Km5Rf4Rza5I/XQqB7IvEL51oTxPZmbCBAgQIDAIAQE9EHsZoMkQIAAgYUIJLwfleXWpiq0zzZfk+dNBy+wM6vsSFUAf9k8IfzZPG8iQIAAAQKDFxDQB/8SAECAAAECCxVIgF+dZdemxgP8Cfm5gvtrxuYV9IcwVbD+V6oCeDN/LI/3C+IJ4E/mORMBAgQIECAwj4CAPg+QXxMgQIAAgYMVGJ2JbwL7zPA+28/HZht16X1Thx7sNhe5/ItZry4hb+qpPB4P203onjnft4wz34tUtxoBAgQIEJhDQECfA8bTBAgQIEBgpQQS8Os+70emKrA38/HHzXPj8+ru7lSF7bnm+/0uAbvuE24iQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAA4nty+wAAB2JJREFUAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgd4J/B+dcycNJZZ/4gAAAABJRU5ErkJggg=='%3E%3C/image%3E%3Crect id='text' fill='%23E2E4E7' x='124' y='173' width='106' height='13'%3E%3C/rect%3E%3Crect id='text' fill='%23E2E4E7' x='124' y='137' width='106' height='13'%3E%3C/rect%3E%3Crect id='text' fill='%23E2E4E7' x='124' y='191' width='106' height='13'%3E%3C/rect%3E%3Crect id='text' fill='%23E2E4E7' x='124' y='245' width='106' height='13'%3E%3C/rect%3E%3Crect id='text' fill='%23E2E4E7' x='124' y='155' width='106' height='13'%3E%3C/rect%3E%3Crect id='text' fill='%23E2E4E7' x='124' y='209' width='106' height='13'%3E%3C/rect%3E%3Crect id='text' fill='%23E2E4E7' x='124' y='263' width='106' height='13'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E" + src="data:image/svg+xml,%3Csvg width='306' height='286' viewBox='0 0 306 286' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='306' height='286' rx='4' fill='%231386BF'/%3E%3Cpath d='M45 32C45 30.8954 45.8954 30 47 30H259C260.105 30 261 30.8954 261 32V286H45V32Z' fill='white'/%3E%3Cpath d='M45 32C45 30.8954 45.8954 30 47 30H259C260.105 30 261 30.8954 261 32V72H45V32Z' fill='%231E1E1E'/%3E%3Crect x='90' y='98' width='104' height='16' fill='%23DDDDDD'/%3E%3Crect x='90' y='129' width='126' height='8' fill='%23DDDDDD'/%3E%3Crect x='90' y='142' width='126' height='8' fill='%23DDDDDD'/%3E%3Crect x='90' y='155' width='126' height='8' fill='%23DDDDDD'/%3E%3Crect x='90' y='209' width='126' height='8' fill='%23DDDDDD'/%3E%3Crect x='90' y='168' width='126' height='8' fill='%23DDDDDD'/%3E%3Crect x='90' y='222' width='126' height='8' fill='%23DDDDDD'/%3E%3Crect x='90' y='181' width='63' height='8' fill='%23DDDDDD'/%3E%3Crect x='90' y='235' width='63' height='8' fill='%23DDDDDD'/%3E%3Cpath d='M78.6668 50.9999C78.6668 44.5716 73.4285 39.3333 67.0002 39.3333C60.5602 39.3333 55.3335 44.5716 55.3335 50.9999C55.3335 57.4399 60.5602 62.6666 67.0002 62.6666C73.4285 62.6666 78.6668 57.4399 78.6668 50.9999ZM64.4102 57.2649L60.4318 46.5899C61.0735 46.5666 61.7968 46.4966 61.7968 46.4966C62.3802 46.4266 62.3102 45.1783 61.7268 45.2016C61.7268 45.2016 60.0352 45.3299 58.9618 45.3299C58.7518 45.3299 58.5302 45.3299 58.2852 45.3183C60.1402 42.4716 63.3485 40.6283 67.0002 40.6283C69.7185 40.6283 72.1918 41.6433 74.0585 43.3583C73.2652 43.2299 72.1335 43.8133 72.1335 45.2016C72.1335 46.0649 72.6585 46.7883 73.1835 47.6516C73.5918 48.3633 73.8252 49.2383 73.8252 50.5216C73.8252 52.2599 72.1918 56.3549 72.1918 56.3549L68.6568 46.5899C69.2868 46.5666 69.6135 46.3916 69.6135 46.3916C70.1968 46.3333 70.1268 44.9333 69.5435 44.9683C69.5435 44.9683 67.8635 45.1083 66.7668 45.1083C65.7518 45.1083 64.0485 44.9683 64.0485 44.9683C63.4652 44.9333 63.3952 46.3683 63.9785 46.3916L65.0518 46.4849L66.5218 50.4633L64.4102 57.2649ZM75.6452 50.9999C75.9252 50.2533 76.5085 48.8183 76.1468 46.0416C76.9635 47.5466 77.3718 49.2033 77.3718 50.9999C77.3718 54.8383 75.3535 58.2799 72.2385 60.0766C73.3702 57.0549 74.5018 54.0099 75.6452 50.9999ZM62.4502 60.4383C58.9735 58.7583 56.6285 55.1183 56.6285 50.9999C56.6285 49.4833 56.8968 48.1066 57.4685 46.8116C59.1252 51.3499 60.7818 55.8999 62.4502 60.4383ZM67.1518 52.7033L70.1618 60.8466C69.1585 61.1849 68.1085 61.3716 67.0002 61.3716C66.0785 61.3716 65.1685 61.2433 64.3285 60.9866C65.2735 58.2099 66.2185 55.4566 67.1518 52.7033V52.7033Z' fill='white'/%3E%3C/svg%3E%0A" { ...props } /> ); @@ -38,7 +38,7 @@ export const DocumentationImage = ( props ) => ( export const InserterIconImage = ( props ) => ( <img alt={ __( 'inserter' ) } - src="data:image/svg+xml;charset=utf8,%3Csvg width='18' height='18' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M8.824 0C3.97 0 0 3.97 0 8.824c0 4.853 3.97 8.824 8.824 8.824 4.853 0 8.824-3.971 8.824-8.824S13.677 0 8.824 0zM7.94 5.294v2.647H5.294v1.765h2.647v2.647h1.765V9.706h2.647V7.941H9.706V5.294H7.941zm-6.176 3.53c0 3.882 3.176 7.059 7.059 7.059 3.882 0 7.059-3.177 7.059-7.06 0-3.882-3.177-7.058-7.06-7.058-3.882 0-7.058 3.176-7.058 7.059z' fill='%234A4A4A'/%3E%3Cmask id='a' maskUnits='userSpaceOnUse' x='0' y='0' width='18' height='18'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M8.824 0C3.97 0 0 3.97 0 8.824c0 4.853 3.97 8.824 8.824 8.824 4.853 0 8.824-3.971 8.824-8.824S13.677 0 8.824 0zM7.94 5.294v2.647H5.294v1.765h2.647v2.647h1.765V9.706h2.647V7.941H9.706V5.294H7.941zm-6.176 3.53c0 3.882 3.176 7.059 7.059 7.059 3.882 0 7.059-3.177 7.059-7.06 0-3.882-3.177-7.058-7.06-7.058-3.882 0-7.058 3.176-7.058 7.059z' fill='%23fff'/%3E%3C/mask%3E%3Cg mask='url(%23a)'%3E%3Cpath fill='%23444' d='M0 0h17.644v17.644H0z'/%3E%3C/g%3E%3C/svg%3E" + src="data:image/svg+xml,%3Csvg width='18' height='18' viewBox='0 0 18 18' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='18' height='18' rx='2' fill='%231E1E1E'/%3E%3Cpath d='M9.22727 4V14M4 8.77273H14' stroke='white' stroke-width='1.5'/%3E%3C/svg%3E%0A" { ...props } /> ); diff --git a/packages/edit-post/src/index.js b/packages/edit-post/src/index.js index 086553ee738b61..1d5475c63535f8 100644 --- a/packages/edit-post/src/index.js +++ b/packages/edit-post/src/index.js @@ -113,14 +113,14 @@ export function initializeEditor( // Without this hack the browser scrolls the mobile toolbar off-screen. // Once supported in Safari we can replace this in favor of preventScroll. // For details see issue #18632 and PR #18686 - // Specifically, we scroll `block-editor-editor-skeleton__body` to enable a fixed top toolbar. + // Specifically, we scroll `interface-interface-skeleton__body` to enable a fixed top toolbar. // But Mobile Safari forces the `html` element to scroll upwards, hiding the toolbar. const isIphone = window.navigator.userAgent.indexOf( 'iPhone' ) !== -1; if ( isIphone ) { window.addEventListener( 'scroll', function( event ) { const editorScrollContainer = document.getElementsByClassName( - 'block-editor-editor-skeleton__body' + 'interface-interface-skeleton__body' )[ 0 ]; if ( event.target === document ) { // Scroll element into view by scrolling the editor container by the same amount diff --git a/packages/edit-post/src/plugins/block-patterns/index.js b/packages/edit-post/src/plugins/block-patterns/index.js deleted file mode 100644 index e9018bbfd3ed91..00000000000000 --- a/packages/edit-post/src/plugins/block-patterns/index.js +++ /dev/null @@ -1,42 +0,0 @@ -/** - * WordPress dependencies - */ -import { layout } from '@wordpress/icons'; -import { __ } from '@wordpress/i18n'; -import { __experimentalBlockPatterns as BlockPatternsList } from '@wordpress/block-editor'; -import { useSelect } from '@wordpress/data'; - -/** - * Internal dependencies - */ -import PluginSidebar from '../../components/sidebar/plugin-sidebar'; -import PluginSidebarMoreMenuItem from '../../components/header/plugin-sidebar-more-menu-item'; - -function BlockPatterns() { - const { __experimentalBlockPatterns: blockPatterns = [] } = useSelect( - ( select ) => { - return select( 'core/editor' ).getEditorSettings(); - }, - [] - ); - - return ( - <> - <PluginSidebar - icon={ layout } - name="block-patterns-sidebar" - title={ __( 'Block Patterns' ) } - > - <BlockPatternsList patterns={ blockPatterns } /> - </PluginSidebar> - <PluginSidebarMoreMenuItem - icon={ layout } - target="block-patterns-sidebar" - > - { __( 'Block Patterns' ) } - </PluginSidebarMoreMenuItem> - </> - ); -} - -export default BlockPatterns; diff --git a/packages/edit-post/src/plugins/index.js b/packages/edit-post/src/plugins/index.js index 1ea4d15f1a500d..cbdc9b2bb7ace7 100644 --- a/packages/edit-post/src/plugins/index.js +++ b/packages/edit-post/src/plugins/index.js @@ -14,13 +14,6 @@ import ManageBlocksMenuItem from './manage-blocks-menu-item'; import KeyboardShortcutsHelpMenuItem from './keyboard-shortcuts-help-menu-item'; import ToolsMoreMenuGroup from '../components/header/tools-more-menu-group'; import WelcomeGuideMenuItem from './welcome-guide-menu-item'; -import BlockPatterns from './block-patterns'; - -registerPlugin( 'edit-post-block-patterns', { - render() { - return <BlockPatterns />; - }, -} ); registerPlugin( 'edit-post', { render() { @@ -48,7 +41,8 @@ registerPlugin( 'edit-post', { href={ __( 'https://wordpress.org/support/article/wordpress-editor/' ) } - target="_new" + target="_blank" + rel="noopener noreferrer" > { __( 'Help' ) } </MenuItem> diff --git a/packages/edit-post/src/store/actions.js b/packages/edit-post/src/store/actions.js index eec8afd6b38240..33140b34f7d09d 100644 --- a/packages/edit-post/src/store/actions.js +++ b/packages/edit-post/src/store/actions.js @@ -3,29 +3,38 @@ */ import { castArray } from 'lodash'; +/** + * WordPress dependencies + */ +import { dispatch } from '@wordpress/data-controls'; + /** * Returns an action object used in signalling that the user opened an editor sidebar. * - * @param {string} name Sidebar name to be opened. + * @param {?string} name Sidebar name to be opened. * - * @return {Object} Action object. + * @yield {Object} Action object. */ -export function openGeneralSidebar( name ) { - return { - type: 'OPEN_GENERAL_SIDEBAR', - name, - }; +export function* openGeneralSidebar( name ) { + yield dispatch( + 'core/interface', + 'enableComplementaryArea', + 'core/edit-post', + name + ); } /** * Returns an action object signalling that the user closed the sidebar. * - * @return {Object} Action object. + * @yield {Object} Action object. */ -export function closeGeneralSidebar() { - return { - type: 'CLOSE_GENERAL_SIDEBAR', - }; +export function* closeGeneralSidebar() { + yield dispatch( + 'core/interface', + 'disableComplementaryArea', + 'core/edit-post' + ); } /** diff --git a/packages/edit-post/src/store/defaults.js b/packages/edit-post/src/store/defaults.js index 1b90986e222a9a..64435c05ce74c1 100644 --- a/packages/edit-post/src/store/defaults.js +++ b/packages/edit-post/src/store/defaults.js @@ -1,6 +1,5 @@ export const PREFERENCES_DEFAULTS = { editorMode: 'visual', - isGeneralSidebarDismissed: false, panels: { 'post-status': { opened: true, @@ -11,7 +10,6 @@ export const PREFERENCES_DEFAULTS = { welcomeGuide: true, fullscreenMode: true, }, - pinnedPluginItems: {}, hiddenBlockTypes: [], preferredStyleVariations: {}, localAutosaveInterval: 15, diff --git a/packages/edit-post/src/store/defaults.native.js b/packages/edit-post/src/store/defaults.native.js deleted file mode 100644 index 7ac420b872cadc..00000000000000 --- a/packages/edit-post/src/store/defaults.native.js +++ /dev/null @@ -1,14 +0,0 @@ -export const PREFERENCES_DEFAULTS = { - editorMode: 'visual', - isGeneralSidebarDismissed: true, - panels: { - 'post-status': { - opened: true, - }, - }, - features: { - fixedToolbar: true, - }, - pinnedPluginItems: {}, - hiddenBlockTypes: [], -}; diff --git a/packages/edit-post/src/store/index.js b/packages/edit-post/src/store/index.js index 4560fd12d46bbb..de84aaf3062ab0 100644 --- a/packages/edit-post/src/store/index.js +++ b/packages/edit-post/src/store/index.js @@ -2,6 +2,7 @@ * WordPress dependencies */ import { registerStore } from '@wordpress/data'; +import { controls as dataControls } from '@wordpress/data-controls'; /** * Internal dependencies @@ -17,7 +18,10 @@ const store = registerStore( STORE_KEY, { reducer, actions, selectors, - controls, + controls: { + ...dataControls, + ...controls, + }, persist: [ 'preferences' ], } ); diff --git a/packages/edit-post/src/store/reducer.js b/packages/edit-post/src/store/reducer.js index 27e5c29493976a..6f77bb46e0937b 100644 --- a/packages/edit-post/src/store/reducer.js +++ b/packages/edit-post/src/store/reducer.js @@ -13,13 +13,6 @@ import { combineReducers } from '@wordpress/data'; */ import { PREFERENCES_DEFAULTS } from './defaults'; -/** - * The default active general sidebar: The "Document" tab. - * - * @type {string} - */ -export const DEFAULT_ACTIVE_GENERAL_SIDEBAR = 'edit-post/document'; - /** * Higher-order reducer creator which provides the given initial state for the * original reducer. @@ -55,15 +48,6 @@ export const preferences = flow( [ combineReducers, createWithInitialState( PREFERENCES_DEFAULTS ), ] )( { - isGeneralSidebarDismissed( state, action ) { - switch ( action.type ) { - case 'OPEN_GENERAL_SIDEBAR': - case 'CLOSE_GENERAL_SIDEBAR': - return action.type === 'CLOSE_GENERAL_SIDEBAR'; - } - - return state; - }, panels( state, action ) { switch ( action.type ) { case 'TOGGLE_PANEL_ENABLED': { @@ -111,19 +95,6 @@ export const preferences = flow( [ return state; }, - pinnedPluginItems( state, action ) { - if ( action.type === 'TOGGLE_PINNED_PLUGIN_ITEM' ) { - return { - ...state, - [ action.pluginName ]: ! get( - state, - [ action.pluginName ], - true - ), - }; - } - return state; - }, hiddenBlockTypes( state, action ) { switch ( action.type ) { case 'SHOW_BLOCK_TYPES': @@ -181,27 +152,6 @@ export function removedPanels( state = [], action ) { return state; } -/** - * Reducer returning the next active general sidebar state. The active general - * sidebar is a unique name to identify either an editor or plugin sidebar. - * - * @param {?string} state Current state. - * @param {Object} action Action object. - * - * @return {?string} Updated state. - */ -export function activeGeneralSidebar( - state = DEFAULT_ACTIVE_GENERAL_SIDEBAR, - action -) { - switch ( action.type ) { - case 'OPEN_GENERAL_SIDEBAR': - return action.name; - } - - return state; -} - /** * Reducer for storing the name of the open modal, or null if no modal is open. * @@ -294,7 +244,6 @@ const metaBoxes = combineReducers( { } ); export default combineReducers( { - activeGeneralSidebar, activeModal, metaBoxes, preferences, diff --git a/packages/edit-post/src/store/selectors.js b/packages/edit-post/src/store/selectors.js index d2742fb3fe181c..fd99d43279462c 100644 --- a/packages/edit-post/src/store/selectors.js +++ b/packages/edit-post/src/store/selectors.js @@ -4,6 +4,11 @@ import createSelector from 'rememo'; import { get, includes, some, flatten, values } from 'lodash'; +/** + * WordPress dependencies + */ +import { createRegistrySelector } from '@wordpress/data'; + /** * Returns the current editing mode. * @@ -22,14 +27,17 @@ export function getEditorMode( state ) { * * @return {boolean} Whether the editor sidebar is opened. */ -export function isEditorSidebarOpened( state ) { - const activeGeneralSidebar = getActiveGeneralSidebarName( state ); - - return includes( - [ 'edit-post/document', 'edit-post/block' ], - activeGeneralSidebar - ); -} +export const isEditorSidebarOpened = createRegistrySelector( + ( select ) => () => { + const activeGeneralSidebar = select( + 'core/interface' + ).getActiveComplementaryArea( 'core/edit-post' ); + return includes( + [ 'edit-post/document', 'edit-post/block' ], + activeGeneralSidebar + ); + } +); /** * Returns true if the plugin sidebar is opened. @@ -37,10 +45,20 @@ export function isEditorSidebarOpened( state ) { * @param {Object} state Global application state * @return {boolean} Whether the plugin sidebar is opened. */ -export function isPluginSidebarOpened( state ) { - const activeGeneralSidebar = getActiveGeneralSidebarName( state ); - return !! activeGeneralSidebar && ! isEditorSidebarOpened( state ); -} +export const isPluginSidebarOpened = createRegistrySelector( + ( select ) => () => { + const activeGeneralSidebar = select( + 'core/interface' + ).getActiveComplementaryArea( 'core/edit-post' ); + return ( + !! activeGeneralSidebar && + ! includes( + [ 'edit-post/document', 'edit-post/block' ], + activeGeneralSidebar + ) + ); + } +); /** * Returns the current active general sidebar name, or null if there is no @@ -56,19 +74,13 @@ export function isPluginSidebarOpened( state ) { * * @return {?string} Active general sidebar name. */ -export function getActiveGeneralSidebarName( state ) { - // Dismissal takes precedent. - const isDismissed = getPreference( - state, - 'isGeneralSidebarDismissed', - false - ); - if ( isDismissed ) { - return null; +export const getActiveGeneralSidebarName = createRegistrySelector( + ( select ) => () => { + return select( 'core/interface' ).getActiveComplementaryArea( + 'core/edit-post' + ); } - - return state.activeGeneralSidebar; -} +); /** * Returns the preferences (these preferences are persisted locally). @@ -187,11 +199,14 @@ export function isFeatureActive( state, feature ) { * * @return {boolean} Whether the plugin item is pinned. */ -export function isPluginItemPinned( state, pluginName ) { - const pinnedPluginItems = getPreference( state, 'pinnedPluginItems', {} ); - - return get( pinnedPluginItems, [ pluginName ], true ); -} +export const isPluginItemPinned = createRegistrySelector( + ( select ) => ( pluginName ) => { + return select( 'core/interface' ).isItemPinned( + 'core/edit-post', + pluginName + ); + } +); /** * Returns an array of active meta box locations. diff --git a/packages/edit-post/src/store/test/actions.js b/packages/edit-post/src/store/test/actions.js index 07dc4b81ece682..31877f378bb286 100644 --- a/packages/edit-post/src/store/test/actions.js +++ b/packages/edit-post/src/store/test/actions.js @@ -5,37 +5,16 @@ import { toggleEditorPanelEnabled, toggleEditorPanelOpened, removeEditorPanel, - openGeneralSidebar, - closeGeneralSidebar, openPublishSidebar, closePublishSidebar, togglePublishSidebar, openModal, closeModal, toggleFeature, - togglePinnedPluginItem, requestMetaBoxUpdates, } from '../actions'; describe( 'actions', () => { - describe( 'openGeneralSidebar', () => { - it( 'should return OPEN_GENERAL_SIDEBAR action', () => { - const name = 'plugin/my-name'; - expect( openGeneralSidebar( name ) ).toEqual( { - type: 'OPEN_GENERAL_SIDEBAR', - name, - } ); - } ); - } ); - - describe( 'closeGeneralSidebar', () => { - it( 'should return CLOSE_GENERAL_SIDEBAR action', () => { - expect( closeGeneralSidebar() ).toEqual( { - type: 'CLOSE_GENERAL_SIDEBAR', - } ); - } ); - } ); - describe( 'openPublishSidebar', () => { it( 'should return an OPEN_PUBLISH_SIDEBAR action', () => { expect( openPublishSidebar() ).toEqual( { @@ -115,17 +94,6 @@ describe( 'actions', () => { } ); } ); - describe( 'togglePinnedPluginItem', () => { - it( 'should return TOGGLE_PINNED_PLUGIN_ITEM action', () => { - const pluginName = 'foo/bar'; - - expect( togglePinnedPluginItem( pluginName ) ).toEqual( { - type: 'TOGGLE_PINNED_PLUGIN_ITEM', - pluginName, - } ); - } ); - } ); - describe( 'requestMetaBoxUpdates', () => { it( 'should return the REQUEST_META_BOX_UPDATES action', () => { expect( requestMetaBoxUpdates() ).toEqual( { diff --git a/packages/edit-post/src/store/test/reducer.js b/packages/edit-post/src/store/test/reducer.js index b21be5ff26d9ba..59a966024bf920 100644 --- a/packages/edit-post/src/store/test/reducer.js +++ b/packages/edit-post/src/store/test/reducer.js @@ -7,9 +7,7 @@ import deepFreeze from 'deep-freeze'; * Internal dependencies */ import { - DEFAULT_ACTIVE_GENERAL_SIDEBAR, preferences, - activeGeneralSidebar, activeModal, isSavingMetaBoxes, metaBoxLocations, @@ -25,30 +23,6 @@ describe( 'state', () => { expect( state ).toEqual( PREFERENCES_DEFAULTS ); } ); - it( 'should set the general sidebar dismissed', () => { - const original = deepFreeze( preferences( undefined, {} ) ); - const state = preferences( original, { - type: 'OPEN_GENERAL_SIDEBAR', - name: 'edit-post/document', - } ); - - expect( state.isGeneralSidebarDismissed ).toBe( false ); - } ); - - it( 'should set the general sidebar undismissed', () => { - const original = deepFreeze( - preferences( undefined, { - type: 'OPEN_GENERAL_SIDEBAR', - name: 'edit-post/document', - } ) - ); - const state = preferences( original, { - type: 'CLOSE_GENERAL_SIDEBAR', - } ); - - expect( state.isGeneralSidebarDismissed ).toBe( true ); - } ); - it( 'should disable panels by default', () => { const original = deepFreeze( { panels: {}, @@ -186,48 +160,6 @@ describe( 'state', () => { expect( state.features ).toEqual( { chicken: false } ); } ); - describe( 'pinnedPluginItems', () => { - const initialState = deepFreeze( { - pinnedPluginItems: { - 'foo/enabled': true, - 'foo/disabled': false, - }, - } ); - - it( 'should disable a pinned plugin flag when the value does not exist', () => { - const state = preferences( initialState, { - type: 'TOGGLE_PINNED_PLUGIN_ITEM', - pluginName: 'foo/does-not-exist', - } ); - - expect( state.pinnedPluginItems[ 'foo/does-not-exist' ] ).toBe( - false - ); - } ); - - it( 'should disable a pinned plugin flag when it is enabled', () => { - const state = preferences( initialState, { - type: 'TOGGLE_PINNED_PLUGIN_ITEM', - pluginName: 'foo/enabled', - } ); - - expect( state.pinnedPluginItems[ 'foo/enabled' ] ).toBe( - false - ); - } ); - - it( 'should enable a pinned plugin flag when it is disabled', () => { - const state = preferences( initialState, { - type: 'TOGGLE_PINNED_PLUGIN_ITEM', - pluginName: 'foo/disabled', - } ); - - expect( state.pinnedPluginItems[ 'foo/disabled' ] ).toBe( - true - ); - } ); - } ); - describe( 'hiddenBlockTypes', () => { it( 'concatenates unique names on disable', () => { const original = deepFreeze( { @@ -257,24 +189,6 @@ describe( 'state', () => { } ); } ); - describe( 'activeGeneralSidebar', () => { - it( 'should default to the default active sidebar', () => { - const state = activeGeneralSidebar( undefined, {} ); - - expect( state ).toBe( DEFAULT_ACTIVE_GENERAL_SIDEBAR ); - } ); - - it( 'should set the general sidebar', () => { - const original = activeGeneralSidebar( undefined, {} ); - const state = activeGeneralSidebar( original, { - type: 'OPEN_GENERAL_SIDEBAR', - name: 'edit-post/document', - } ); - - expect( state ).toBe( 'edit-post/document' ); - } ); - } ); - describe( 'activeModal', () => { it( 'should default to null', () => { const state = activeModal( undefined, {} ); diff --git a/packages/edit-post/src/store/test/selectors.js b/packages/edit-post/src/store/test/selectors.js index 4da4686fc0379e..f2b349890602ae 100644 --- a/packages/edit-post/src/store/test/selectors.js +++ b/packages/edit-post/src/store/test/selectors.js @@ -9,13 +9,9 @@ import deepFreeze from 'deep-freeze'; import { getEditorMode, getPreference, - isEditorSidebarOpened, isEditorPanelOpened, isModalActive, isFeatureActive, - isPluginSidebarOpened, - getActiveGeneralSidebarName, - isPluginItemPinned, hasMetaBoxes, isSavingMetaBoxes, getActiveMetaBoxLocations, @@ -71,114 +67,6 @@ describe( 'selectors', () => { } ); } ); - describe( 'isEditorSidebarOpened', () => { - it( 'should return false when the editor sidebar is not opened', () => { - const state = { - preferences: { - isGeneralSidebarDismissed: true, - }, - activeGeneralSidebar: null, - }; - - expect( isEditorSidebarOpened( state ) ).toBe( false ); - } ); - - it( 'should return false when the editor sidebar is assigned but not opened', () => { - const state = { - preferences: { - isGeneralSidebarDismissed: true, - }, - activeGeneralSidebar: 'edit-post/document', - }; - - expect( isEditorSidebarOpened( state ) ).toBe( false ); - } ); - - it( 'should return false when the plugin sidebar is opened', () => { - const state = { - preferences: { - isGeneralSidebarDismissed: false, - }, - activeGeneralSidebar: 'my-plugin/my-sidebar', - }; - - expect( isEditorSidebarOpened( state ) ).toBe( false ); - } ); - - it( 'should return true when the editor sidebar is opened', () => { - const state = { - preferences: { - isGeneralSidebarDismissed: false, - }, - activeGeneralSidebar: 'edit-post/document', - }; - - expect( isEditorSidebarOpened( state ) ).toBe( true ); - } ); - } ); - - describe( 'isPluginSidebarOpened', () => { - it( 'should return false when the plugin sidebar is not opened', () => { - const state = { - preferences: { - isGeneralSidebarDismissed: true, - }, - activeGeneralSidebar: null, - }; - - expect( isPluginSidebarOpened( state ) ).toBe( false ); - } ); - - it( 'should return false when the editor sidebar is opened', () => { - const state = { - preferences: { - isGeneralSidebarDismissed: false, - }, - activeGeneralSidebar: 'edit-post/document', - }; - - expect( isPluginSidebarOpened( state ) ).toBe( false ); - } ); - - it( 'should return true when the plugin sidebar is opened', () => { - const name = 'plugin-sidebar/my-plugin/my-sidebar'; - const state = { - preferences: { - isGeneralSidebarDismissed: false, - }, - activeGeneralSidebar: name, - }; - - expect( isPluginSidebarOpened( state ) ).toBe( true ); - } ); - } ); - - describe( 'getActiveGeneralSidebarName', () => { - it( 'returns null if dismissed', () => { - const state = { - preferences: { - isGeneralSidebarDismissed: true, - }, - activeGeneralSidebar: 'edit-post/block', - }; - - expect( getActiveGeneralSidebarName( state ) ).toBe( null ); - } ); - - it( 'returns active general sidebar', () => { - const state = { - preferences: { - isGeneralSidebarDismissed: false, - }, - activeGeneralSidebar: 'edit-post/block', - }; - - expect( getActiveGeneralSidebarName( state ) ).toBe( - 'edit-post/block' - ); - } ); - } ); - describe( 'isModalActive', () => { it( 'returns true if the provided name matches the value in the preferences activeModal property', () => { const state = { @@ -394,29 +282,6 @@ describe( 'selectors', () => { } ); } ); - describe( 'isPluginItemPinned', () => { - const state = { - preferences: { - pinnedPluginItems: { - 'foo/pinned': true, - 'foo/unpinned': false, - }, - }, - }; - - it( 'should return true if the flag is not set for the plugin item', () => { - expect( isPluginItemPinned( state, 'foo/unknown' ) ).toBe( true ); - } ); - - it( 'should return true if plugin item is not pinned', () => { - expect( isPluginItemPinned( state, 'foo/pinned' ) ).toBe( true ); - } ); - - it( 'should return false if plugin item item is unpinned', () => { - expect( isPluginItemPinned( state, 'foo/unpinned' ) ).toBe( false ); - } ); - } ); - describe( 'hasMetaBoxes', () => { it( 'should return true if there are active meta boxes', () => { const state = { diff --git a/packages/edit-post/src/style.scss b/packages/edit-post/src/style.scss index e9a85641e28a29..4e6fea9f88bee4 100644 --- a/packages/edit-post/src/style.scss +++ b/packages/edit-post/src/style.scss @@ -1,10 +1,11 @@ $footer-height: $button-size-small; +@import "../../interface/src/style.scss"; + @import "./components/header/style.scss"; @import "./components/header/fullscreen-mode-close/style.scss"; @import "./components/header/header-toolbar/style.scss"; @import "./components/header/more-menu/style.scss"; -@import "./components/header/pinned-plugins/style.scss"; @import "./components/keyboard-shortcut-help-modal/style.scss"; @import "./components/layout/style.scss"; @import "./components/manage-blocks-modal/style.scss"; @@ -19,7 +20,6 @@ $footer-height: $button-size-small; @import "./components/sidebar/post-status/style.scss"; @import "./components/sidebar/post-visibility/style.scss"; @import "./components/sidebar/settings-header/style.scss"; -@import "./components/sidebar/sidebar-header/style.scss"; @import "./components/text-editor/style.scss"; @import "./components/visual-editor/style.scss"; @import "./components/options-modal/style.scss"; diff --git a/packages/edit-site/package.json b/packages/edit-site/package.json index 26bd51227b58d3..bc80f6a174cd24 100644 --- a/packages/edit-site/package.json +++ b/packages/edit-site/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/edit-site", - "version": "1.3.4", + "version": "1.5.1", "description": "Edit Site Page module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -20,7 +20,7 @@ "module": "build-module/index.js", "react-native": "src/index", "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/block-editor": "file:../block-editor", "@wordpress/block-library": "file:../block-library", "@wordpress/blocks": "file:../blocks", @@ -33,8 +33,11 @@ "@wordpress/hooks": "file:../hooks", "@wordpress/i18n": "file:../i18n", "@wordpress/icons": "file:../icons", + "@wordpress/interface": "file:../interface", "@wordpress/media-utils": "file:../media-utils", "@wordpress/notices": "file:../notices", + "@wordpress/plugins": "file:../plugins", + "@wordpress/primitives": "file:../primitives", "@wordpress/url": "file:../url", "file-saver": "^2.0.2", "jszip": "^3.2.2", diff --git a/packages/edit-site/src/components/block-editor/style.scss b/packages/edit-site/src/components/block-editor/style.scss index c0e285bc77546d..a1872f964f952d 100644 --- a/packages/edit-site/src/components/block-editor/style.scss +++ b/packages/edit-site/src/components/block-editor/style.scss @@ -1,4 +1,14 @@ .edit-site-block-editor__block-list { padding-bottom: $grid-unit-30; padding-top: $grid-unit-30 + 5; + + padding-left: $block-padding; + padding-right: $block-padding; + + // Full-wide. (to account for the padddings added above) + .block-editor-block-list__block[data-align="full"], + .block-editor-block-list__block.alignfull { + margin-left: -$block-padding; + margin-right: -$block-padding; + } } diff --git a/packages/edit-site/src/components/editor/index.js b/packages/edit-site/src/components/editor/index.js index ea1b3bbf782c8f..66640b22f41e6f 100644 --- a/packages/edit-site/src/components/editor/index.js +++ b/packages/edit-site/src/components/editor/index.js @@ -16,10 +16,11 @@ import { } from '@wordpress/components'; import { EntityProvider } from '@wordpress/core-data'; import { - __experimentalEditorSkeleton as EditorSkeleton, - __experimentalFullscreenMode as FullscreenMode, + BlockBreadcrumb, + __unstableEditorStyles as EditorStyles, } from '@wordpress/block-editor'; import { useViewportMatch } from '@wordpress/compose'; +import { FullscreenMode, InterfaceSkeleton } from '@wordpress/interface'; /** * Internal dependencies @@ -61,6 +62,7 @@ function Editor( { settings: _settings } ) { return template ? ( <> + <EditorStyles styles={ settings.styles } /> <FullscreenMode isActive={ isFullscreenActive } /> <SlotFillProvider> <DropZoneProvider> @@ -72,7 +74,7 @@ function Editor( { settings: _settings } ) { > <Context.Provider value={ context }> <FocusReturnProvider> - <EditorSkeleton + <InterfaceSkeleton sidebar={ ! isMobile && <Sidebar /> } header={ <Header /> } content={ @@ -82,6 +84,7 @@ function Editor( { settings: _settings } ) { <BlockEditor /> </> } + footer={ <BlockBreadcrumb /> } /> <Popover.Slot /> </FocusReturnProvider> diff --git a/packages/edit-site/src/components/header/feature-toggle/index.js b/packages/edit-site/src/components/header/feature-toggle/index.js new file mode 100644 index 00000000000000..dec13c805690bf --- /dev/null +++ b/packages/edit-site/src/components/header/feature-toggle/index.js @@ -0,0 +1,52 @@ +/** + * External dependencies + */ +import { flow } from 'lodash'; + +/** + * WordPress dependencies + */ +import { useSelect, useDispatch } from '@wordpress/data'; +import { MenuItem, withSpokenMessages } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; +import { check } from '@wordpress/icons'; + +function FeatureToggle( { + feature, + label, + info, + messageActivated, + messageDeactivated, + speak, +} ) { + const speakMessage = () => { + if ( isActive ) { + speak( messageDeactivated || __( 'Feature deactivated' ) ); + } else { + speak( messageActivated || __( 'Feature activated' ) ); + } + }; + + const isActive = useSelect( ( select ) => { + return select( 'core/edit-site' ).isFeatureActive( feature ); + }, [] ); + + const { toggleFeature } = useDispatch( 'core/edit-site' ); + + return ( + <MenuItem + icon={ isActive && check } + isSelected={ isActive } + onClick={ flow( + toggleFeature.bind( null, feature ), + speakMessage + ) } + role="menuitemcheckbox" + info={ info } + > + { label } + </MenuItem> + ); +} + +export default withSpokenMessages( FeatureToggle ); diff --git a/packages/edit-site/src/components/header/fullscreen-mode-close/index.js b/packages/edit-site/src/components/header/fullscreen-mode-close/index.js new file mode 100644 index 00000000000000..e5a14f30af66b0 --- /dev/null +++ b/packages/edit-site/src/components/header/fullscreen-mode-close/index.js @@ -0,0 +1,35 @@ +/** + * WordPress dependencies + */ +import { useSelect } from '@wordpress/data'; +import { Button } from '@wordpress/components'; +import { Path, SVG } from '@wordpress/primitives'; +import { __ } from '@wordpress/i18n'; + +const wordPressLogo = ( + <SVG width="28" height="28" viewBox="0 0 128 128" version="1.1"> + <Path d="M100 61.3c0-6.6-2.4-11.2-4.4-14.7-2.7-4.4-5.2-8.1-5.2-12.5 0-4.9 3.7-9.5 9-9.5h.7c-9.5-8.7-22.1-14-36-14-18.6 0-35 9.6-44.6 24 1.3 0 2.4.1 3.4.1 5.6 0 14.2-.7 14.2-.7 2.9-.2 3.2 4.1.3 4.4 0 0-2.9.3-6.1.5l19.4 57.8 11.7-35L54.1 39c-2.9-.2-5.6-.5-5.6-.5-2.9-.2-2.5-4.6.3-4.4 0 0 8.8.7 14 .7 5.6 0 14.2-.7 14.2-.7 2.9-.2 3.2 4.1.3 4.4 0 0-2.9.3-6.1.5l19.3 57.3L96 78.9c2.6-7.6 4-13 4-17.6zM10.7 64c0 21.1 12.3 39.4 30.1 48L15.3 42.3c-3 6.6-4.6 14-4.6 21.7zm54.2 4.7l-16 46.5c4.8 1.4 9.8 2.2 15.1 2.2 6.2 0 12.2-1.1 17.7-3-.1-.2-.3-.5-.4-.7l-16.4-45zM64 0C28.7 0 0 28.7 0 64s28.7 64 64 64 64-28.7 64-64S99.3 0 64 0zm49.9 97.6c-2.2 3.2-4.6 6.2-7.3 8.9s-5.7 5.2-8.9 7.3c-3.2 2.2-6.7 4-10.2 5.5-7.4 3.1-15.3 4.7-23.4 4.7s-16-1.6-23.4-4.7c-3.6-1.5-7-3.4-10.2-5.5-3.2-2.2-6.2-4.6-8.9-7.3s-5.2-5.7-7.3-8.9c-2.2-3.2-4-6.7-5.5-10.2-3.4-7.4-5-15.3-5-23.4s1.6-16 4.7-23.4c1.5-3.6 3.4-7 5.5-10.2 2.2-3.2 4.6-6.2 7.3-8.9s5.7-5.2 8.9-7.3c3.2-2.2 6.7-4 10.2-5.5C48 5.4 55.9 3.8 64 3.8s16 1.6 23.4 4.7c3.6 1.5 7 3.4 10.2 5.5 3.2 2.2 6.2 4.6 8.9 7.3s5.2 5.7 7.3 8.9c2.2 3.2 4 6.7 5.5 10.2 3.1 7.4 4.7 15.3 4.7 23.4s-1.6 16-4.7 23.4c-1.4 3.8-3.2 7.2-5.4 10.4zm-2.7-53.7c0 5.4-1 11.5-4.1 19.1l-16.3 47.1c15.9-9.2 26.5-26.4 26.5-46.1 0-9.3-2.4-18-6.5-25.6.2 1.7.4 3.5.4 5.5z" /> + </SVG> +); + +function FullscreenModeClose() { + const isActive = useSelect( ( select ) => { + return select( 'core/edit-site' ).isFeatureActive( 'fullscreenMode' ); + }, [] ); + + if ( ! isActive ) { + return null; + } + + return ( + <Button + className="edit-site-fullscreen-mode-close" + icon={ wordPressLogo } + iconSize={ 36 } + href="index.php" + label={ __( 'Back' ) } + /> + ); +} + +export default FullscreenModeClose; diff --git a/packages/edit-site/src/components/header/fullscreen-mode-close/style.scss b/packages/edit-site/src/components/header/fullscreen-mode-close/style.scss new file mode 100644 index 00000000000000..e8b4eb7b781ccd --- /dev/null +++ b/packages/edit-site/src/components/header/fullscreen-mode-close/style.scss @@ -0,0 +1,29 @@ +.edit-site-fullscreen-mode-close.has-icon { + // Do not show the toolbar icon on small screens, + // when Fullscreen Mode is not an option in the "More" menu. + display: none; + + @include break-medium() { + display: flex; + align-items: center; + align-self: stretch; + border: none; + background: #23282e; // WP-admin gray. + color: $white; + border-radius: 0; + height: auto; + width: $header-height; + + &:hover { + background: #32373d; // WP-admin light-gray. + } + + &:active { + color: $white; + } + + &:focus { + box-shadow: inset 0 0 0 $border-width-focus $theme-color, inset 0 0 0 3px $white; + } + } +} diff --git a/packages/edit-site/src/components/header/index.js b/packages/edit-site/src/components/header/index.js index 78c7090d732015..867dc74ed1d15e 100644 --- a/packages/edit-site/src/components/header/index.js +++ b/packages/edit-site/src/components/header/index.js @@ -2,15 +2,24 @@ * WordPress dependencies */ import { useCallback } from '@wordpress/element'; -import { BlockNavigationDropdown, ToolSelector } from '@wordpress/block-editor'; +import { + BlockNavigationDropdown, + ToolSelector, + Inserter, +} from '@wordpress/block-editor'; +import { PinnedItems } from '@wordpress/interface'; /** * Internal dependencies */ import { useEditorContext } from '../editor'; +import FullscreenModeClose from './fullscreen-mode-close'; +import MoreMenu from './more-menu'; import TemplateSwitcher from '../template-switcher'; import SaveButton from '../save-button'; +const inserterToggleProps = { isPrimary: true }; + export default function Header() { const { settings, setSettings } = useEditorContext(); const setActiveTemplateId = useCallback( @@ -42,7 +51,13 @@ export default function Header() { ); return ( <div className="edit-site-header"> + <FullscreenModeClose /> <div className="edit-site-header__toolbar"> + <Inserter + position="bottom right" + showInserterHelpPanel + toggleProps={ inserterToggleProps } + /> <TemplateSwitcher ids={ settings.templateIds } templatePartIds={ settings.templatePartIds } @@ -59,6 +74,8 @@ export default function Header() { </div> <div className="edit-site-header__actions"> <SaveButton /> + <PinnedItems.Slot scope="core/edit-site" /> + <MoreMenu /> </div> </div> ); diff --git a/packages/edit-site/src/components/header/more-menu/index.js b/packages/edit-site/src/components/header/more-menu/index.js new file mode 100644 index 00000000000000..c762ffa60d8946 --- /dev/null +++ b/packages/edit-site/src/components/header/more-menu/index.js @@ -0,0 +1,43 @@ +/** + * WordPress dependencies + */ +import { __, _x } from '@wordpress/i18n'; +import { DropdownMenu, MenuGroup } from '@wordpress/components'; + +/** + * Internal dependencies + */ +import FeatureToggle from '../feature-toggle'; +import { moreVertical } from '@wordpress/icons'; + +const POPOVER_PROPS = { + className: 'edit-site-more-menu__content', + position: 'bottom left', +}; +const TOGGLE_PROPS = { + tooltipPosition: 'bottom', +}; + +const MoreMenu = () => ( + <DropdownMenu + className="edit-site-more-menu" + icon={ moreVertical } + label={ __( 'More tools & options' ) } + popoverProps={ POPOVER_PROPS } + toggleProps={ TOGGLE_PROPS } + > + { () => ( + <MenuGroup label={ _x( 'View', 'noun' ) }> + <FeatureToggle + feature="fullscreenMode" + label={ __( 'Fullscreen mode' ) } + info={ __( 'Work without distraction' ) } + messageActivated={ __( 'Fullscreen mode activated' ) } + messageDeactivated={ __( 'Fullscreen mode deactivated' ) } + /> + </MenuGroup> + ) } + </DropdownMenu> +); + +export default MoreMenu; diff --git a/packages/edit-site/src/components/header/more-menu/style.scss b/packages/edit-site/src/components/header/more-menu/style.scss new file mode 100644 index 00000000000000..6151efb026a189 --- /dev/null +++ b/packages/edit-site/src/components/header/more-menu/style.scss @@ -0,0 +1,29 @@ +.edit-site-more-menu { + margin-left: -4px; + + // the padding and margin of the more menu is intentionally non-standard + .components-button { + width: auto; + padding: 0 2px; + } + + @include break-small() { + margin-left: 4px; + + .components-button { + padding: 0 4px; + } + } +} + +.edit-site-more-menu__content .components-popover__content { + min-width: 260px; + + .components-dropdown-menu__menu { + padding: 0; + } +} + +.components-popover.edit-site-more-menu__content { + z-index: z-index(".components-popover.edit-site-more-menu__content"); +} diff --git a/packages/edit-site/src/components/header/style.scss b/packages/edit-site/src/components/header/style.scss index 43b1422aa1251c..80c91d2880b8ec 100644 --- a/packages/edit-site/src/components/header/style.scss +++ b/packages/edit-site/src/components/header/style.scss @@ -3,18 +3,22 @@ display: flex; height: $header-height; justify-content: space-between; - padding: $grid-unit-10; box-sizing: border-box; } -.edit-site-header__toolbar, -.edit-site-header__actions { +.edit-site-header__toolbar { display: flex; + flex-grow: 1; + padding-left: $grid-unit-10; & > * { margin-left: 5px; } } +.edit-site-header__actions { + display: flex; + margin-right: 8px; +} .edit-site-header__actions-more-menu { margin-left: -4px; diff --git a/packages/edit-site/src/components/save-button/index.js b/packages/edit-site/src/components/save-button/index.js index 410f8d5970d399..28af9be05d723b 100644 --- a/packages/edit-site/src/components/save-button/index.js +++ b/packages/edit-site/src/components/save-button/index.js @@ -53,12 +53,13 @@ export default function SaveButton() { const disabled = ! isDirty || isSaving; const [ isOpen, setIsOpen ] = useState( false ); - const open = useCallback( setIsOpen.bind( null, true ), [] ); - const close = useCallback( setIsOpen.bind( null, false ), [] ); + const open = useCallback( () => setIsOpen( true ), [] ); + const close = useCallback( () => setIsOpen( false ), [] ); return ( <> <Button isPrimary + className="edit-site-save-button__button" aria-disabled={ disabled } disabled={ disabled } isBusy={ isSaving } diff --git a/packages/edit-site/src/components/sidebar/index.js b/packages/edit-site/src/components/sidebar/index.js index 060c2ddce1a510..f5ee7eda2d9a23 100644 --- a/packages/edit-site/src/components/sidebar/index.js +++ b/packages/edit-site/src/components/sidebar/index.js @@ -1,20 +1,35 @@ /** * WordPress dependencies */ -import { createSlotFill, Panel } from '@wordpress/components'; +import { createSlotFill } from '@wordpress/components'; +import { ComplementaryArea } from '@wordpress/interface'; import { __ } from '@wordpress/i18n'; +import { cog, pencil } from '@wordpress/icons'; const { Slot: InspectorSlot, Fill: InspectorFill } = createSlotFill( 'EditSiteSidebarInspector' ); - function Sidebar() { return ( - <div className="edit-site-sidebar"> - <Panel header={ __( 'Inspector' ) }> + <> + <ComplementaryArea.Slot scope="core/edit-site" /> + <ComplementaryArea + scope="core/edit-site" + complementaryAreaIdentifier="edit-site/block-inspector" + title={ __( 'Block Inspector' ) } + icon={ cog } + > <InspectorSlot bubblesVirtually /> - </Panel> - </div> + </ComplementaryArea> + <ComplementaryArea + scope="core/edit-site" + complementaryAreaIdentifier="edit-site/global-styles" + title={ __( 'Global Styles' ) } + icon={ pencil } + > + <p>Global Styles area</p> + </ComplementaryArea> + </> ); } diff --git a/packages/edit-site/src/components/template-switcher/index.js b/packages/edit-site/src/components/template-switcher/index.js index d3192ac9a718dd..780ddf1982bda8 100644 --- a/packages/edit-site/src/components/template-switcher/index.js +++ b/packages/edit-site/src/components/template-switcher/index.js @@ -6,35 +6,30 @@ import { useSelect } from '@wordpress/data'; import { useState, useCallback } from '@wordpress/element'; import { Tooltip, - Icon, DropdownMenu, MenuGroup, MenuItemsChoice, MenuItem, } from '@wordpress/components'; -import { layout, plus } from '@wordpress/icons'; +import { plus } from '@wordpress/icons'; /** * Internal dependencies */ import AddTemplate from '../add-template'; -import TemplatePreview from './preview'; +import TemplatePreview from './template-preview'; +import ThemePreview from './theme-preview'; function TemplateLabel( { template } ) { return ( - <div className="edit-site-template-switcher__label"> + <> { template.slug }{ ' ' } { template.status !== 'auto-draft' && ( <Tooltip text={ __( 'Customized' ) }> - <div className="edit-site-template-switcher__label-customized-icon-container"> - <Icon - icon="marker" - className="edit-site-template-switcher__label-customized-icon-icon" - /> - </div> + <span className="edit-site-template-switcher__label-customized-dot" /> </Tooltip> ) } - </div> + </> ); } @@ -48,16 +43,27 @@ export default function TemplateSwitcher( { onAddTemplateId, } ) { const [ hoveredTemplate, setHoveredTemplate ] = useState(); + const [ themePreviewVisible, setThemePreviewVisible ] = useState( false ); + const onHoverTemplate = ( id ) => { setHoveredTemplate( { id, type: 'template' } ); }; const onHoverTemplatePart = ( id ) => { setHoveredTemplate( { id, type: 'template-part' } ); }; - const { templates, templateParts } = useSelect( + + const onMouseEnterTheme = () => { + setThemePreviewVisible( () => true ); + }; + const onMouseLeaveTheme = () => { + setThemePreviewVisible( () => false ); + }; + + const { currentTheme, templates, templateParts } = useSelect( ( select ) => { - const { getEntityRecord } = select( 'core' ); + const { getCurrentTheme, getEntityRecord } = select( 'core' ); return { + currentTheme: getCurrentTheme(), templates: ids.map( ( id ) => { const template = getEntityRecord( 'postType', @@ -68,10 +74,10 @@ export default function TemplateSwitcher( { label: template ? ( <TemplateLabel template={ template } /> ) : ( - __( 'loading…' ) + __( 'Loading…' ) ), value: id, - slug: template ? template.slug : __( 'loading…' ), + slug: template ? template.slug : __( 'Loading…' ), }; } ), templateParts: templatePartIds.map( ( id ) => { @@ -84,10 +90,10 @@ export default function TemplateSwitcher( { label: template ? ( <TemplateLabel template={ template } /> ) : ( - __( 'loading…' ) + __( 'Loading…' ) ), value: id, - slug: template ? template.slug : __( 'loading…' ), + slug: template ? template.slug : __( 'Loading…' ), }; } ), }; @@ -102,7 +108,7 @@ export default function TemplateSwitcher( { className: 'edit-site-template-switcher__popover', position: 'bottom right', } } - icon={ layout } + icon={ null } label={ __( 'Switch Template' ) } toggleProps={ { children: ( isTemplatePart @@ -140,9 +146,21 @@ export default function TemplateSwitcher( { onHover={ onHoverTemplatePart } /> </MenuGroup> + <MenuGroup label={ __( 'Current theme' ) }> + <MenuItem + onMouseEnter={ onMouseEnterTheme } + onMouseLeave={ onMouseLeaveTheme } + > + { currentTheme.name } + </MenuItem> + </MenuGroup> { !! hoveredTemplate?.id && ( <TemplatePreview item={ hoveredTemplate } /> ) } + { themePreviewVisible && ( + <ThemePreview theme={ currentTheme } /> + ) } + <div className="edit-site-template-switcher__footer" /> </> ) } </DropdownMenu> diff --git a/packages/edit-site/src/components/template-switcher/style.scss b/packages/edit-site/src/components/template-switcher/style.scss index a7a410472fd961..d1d8680e30a0ed 100644 --- a/packages/edit-site/src/components/template-switcher/style.scss +++ b/packages/edit-site/src/components/template-switcher/style.scss @@ -2,23 +2,36 @@ overflow: visible; } -.edit-site-template-switcher__label { +.edit-site-template-switcher__popover .components-menu-item__button { position: relative; - width: 100%; } -.edit-site-template-switcher__label-customized-icon-container { +.edit-site-template-switcher__label-customized-dot { position: absolute; - right: 5px; - top: 0; - width: 10px; + right: 4px; + top: 50%; + margin-top: -4px; + width: 8px; + height: 8px; + display: block; + background: $theme-color; + border-radius: 50%; } .edit-site-template-switcher__label-customized-icon-icon { width: 100%; } -.edit-site-template-switcher__preview { +/* + * This doesn't contain anything but it's needed because of dropdown jumpiness + * when there's a div after the last menu group. + */ +.edit-site-template-switcher__footer { + margin-bottom: -$grid-unit-15; +} + +.edit-site-template-switcher__template-preview, +.edit-site-template-switcher__theme-preview { display: none; border: $border-width solid $light-gray-secondary; width: 300px; @@ -30,8 +43,18 @@ top: -$border-width; left: calc(100% + #{$grid-unit-15}); - @include break-medium { display: block; } } + +.edit-site-template-switcher__theme-preview-name { + font-weight: 500; + font-size: $big-font-size; +} + +.edit-site-template-switcher__theme-preview-screenshot { + margin-bottom: $grid-unit-15; + margin-top: $grid-unit-15; + max-width: 100%; +} diff --git a/packages/edit-site/src/components/template-switcher/preview.js b/packages/edit-site/src/components/template-switcher/template-preview.js similarity index 80% rename from packages/edit-site/src/components/template-switcher/preview.js rename to packages/edit-site/src/components/template-switcher/template-preview.js index 03cf6399e8d916..c53b4ec1c0795f 100644 --- a/packages/edit-site/src/components/template-switcher/preview.js +++ b/packages/edit-site/src/components/template-switcher/template-preview.js @@ -22,8 +22,10 @@ function TemplatePreview( { item } ) { [ template ] ); return ( - <div className="edit-site-template-switcher__preview"> - { !! blocks && <BlockPreview blocks={ blocks } autoHeight /> } + <div className="edit-site-template-switcher__template-preview"> + { !! blocks && ( + <BlockPreview blocks={ blocks } viewportWidth={ 1200 } /> + ) } </div> ); } diff --git a/packages/edit-site/src/components/template-switcher/theme-preview.js b/packages/edit-site/src/components/template-switcher/theme-preview.js new file mode 100644 index 00000000000000..acb9ba3a40f466 --- /dev/null +++ b/packages/edit-site/src/components/template-switcher/theme-preview.js @@ -0,0 +1,41 @@ +/** + * External dependencies + */ +import { truncate } from 'lodash'; + +/** + * WordPress dependencies + */ +import { __, sprintf } from '@wordpress/i18n'; + +function ThemePreview( { + theme: { author_name: authorName, description, name, screenshot, version }, +} ) { + return ( + <div className="edit-site-template-switcher__theme-preview"> + <span className="edit-site-template-switcher__theme-preview-name"> + { name } + </span>{ ' ' } + <span className="edit-site-template-switcher__theme-preview-version"> + { 'v' + version } + </span> + <div className="edit-site-template-switcher__theme-preview-byline"> + { // translators: %s: theme author name. + sprintf( __( 'By %s' ), [ authorName ] ) } + </div> + <img + className="edit-site-template-switcher__theme-preview-screenshot" + src={ screenshot } + alt={ 'Theme Preview' } + /> + <div className="edit-site-template-switcher__theme-preview-description"> + { truncate( description, { + length: 120, + separator: /\. +/, + } ) } + </div> + </div> + ); +} + +export default ThemePreview; diff --git a/packages/edit-site/src/store/defaults.js b/packages/edit-site/src/store/defaults.js index 3385189ea64ee5..b7f95f64d6cfb8 100644 --- a/packages/edit-site/src/store/defaults.js +++ b/packages/edit-site/src/store/defaults.js @@ -1,5 +1,5 @@ export const PREFERENCES_DEFAULTS = { features: { - fullscreenMode: false, + fullscreenMode: true, }, }; diff --git a/packages/edit-site/src/style.scss b/packages/edit-site/src/style.scss index 4bbd782ccf5975..a2a4c6023f3403 100644 --- a/packages/edit-site/src/style.scss +++ b/packages/edit-site/src/style.scss @@ -1,5 +1,9 @@ +@import "../../interface/src/style.scss"; + @import "./components/block-editor/style.scss"; @import "./components/header/style.scss"; +@import "./components/header/fullscreen-mode-close/style.scss"; +@import "./components/header/more-menu/style.scss"; @import "./components/notices/style.scss"; @import "./components/sidebar/style.scss"; @import "./components/template-switcher/style.scss"; @@ -10,7 +14,6 @@ html.wp-toolbar { background: $white; } -body.gutenberg_page_gutenberg-edit-site, body.toplevel_page_gutenberg-edit-site { @include wp-admin-reset(".edit-site"); } @@ -41,6 +44,12 @@ body.toplevel_page_gutenberg-edit-site { > .components-navigate-regions { height: 100%; } + + // Todo: Remove this rule when edit site gets support + // for opening unpinned sidebar items. + .interface-complementary-area__pin-unpin-item.components-button { + display: none; + } } /** diff --git a/packages/edit-widgets/package.json b/packages/edit-widgets/package.json index 5c02dc6e9e428c..d84bccbd764555 100644 --- a/packages/edit-widgets/package.json +++ b/packages/edit-widgets/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/edit-widgets", - "version": "0.12.5", + "version": "0.14.1", "private": true, "description": "Widgets Page module for WordPress..", "author": "The WordPress Contributors", @@ -21,7 +21,7 @@ "module": "build-module/index.js", "react-native": "src/index", "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/block-editor": "file:../block-editor", "@wordpress/block-library": "file:../block-library", "@wordpress/blocks": "file:../blocks", @@ -32,6 +32,7 @@ "@wordpress/element": "file:../element", "@wordpress/hooks": "file:../hooks", "@wordpress/i18n": "file:../i18n", + "@wordpress/interface": "file:../interface", "@wordpress/media-utils": "file:../media-utils", "@wordpress/notices": "file:../notices", "lodash": "^4.17.15", diff --git a/packages/edit-widgets/src/components/layout/index.js b/packages/edit-widgets/src/components/layout/index.js index 5f5c4424b3909c..97b6c6b2ea9d8a 100644 --- a/packages/edit-widgets/src/components/layout/index.js +++ b/packages/edit-widgets/src/components/layout/index.js @@ -8,11 +8,9 @@ import { FocusReturnProvider, } from '@wordpress/components'; import { useState } from '@wordpress/element'; -import { - BlockEditorKeyboardShortcuts, - __experimentalEditorSkeleton as EditorSkeleton, -} from '@wordpress/block-editor'; +import { BlockEditorKeyboardShortcuts } from '@wordpress/block-editor'; import { useViewportMatch } from '@wordpress/compose'; +import { InterfaceSkeleton } from '@wordpress/interface'; /** * Internal dependencies @@ -32,7 +30,7 @@ function Layout( { blockEditorSettings } ) { <SlotFillProvider> <DropZoneProvider> <FocusReturnProvider> - <EditorSkeleton + <InterfaceSkeleton header={ <Header /> } sidebar={ ! isMobile && <Sidebar /> } content={ diff --git a/packages/edit-widgets/src/components/widget-area/style.scss b/packages/edit-widgets/src/components/widget-area/style.scss index 2f1160bd17c77b..248f5d4e4ff856 100644 --- a/packages/edit-widgets/src/components/widget-area/style.scss +++ b/packages/edit-widgets/src/components/widget-area/style.scss @@ -2,11 +2,6 @@ max-width: $widget-area-width; margin: 0 auto 30px; - // Reduce padding inside widget areas - .block-editor-block-list__layout { - padding-left: $block-side-ui-width + $block-padding; - padding-right: $block-side-ui-width + $block-padding; - } // By default the default block appender inserter has a negative position, // but given that on the widget screen we have 0 padding we need to remove the negative position. .block-editor-default-block-appender .block-editor-inserter, diff --git a/packages/edit-widgets/src/style.scss b/packages/edit-widgets/src/style.scss index 86ee2bd54c3c69..41cc5979e9dd6e 100644 --- a/packages/edit-widgets/src/style.scss +++ b/packages/edit-widgets/src/style.scss @@ -1,3 +1,5 @@ +@import "../../interface/src/style.scss"; + @import "./components/customizer-edit-widgets-initializer/style.scss"; @import "./components/header/style.scss"; @import "./components/layout/style.scss"; @@ -49,7 +51,7 @@ body.gutenberg_page_gutenberg-widgets { } - .block-editor-editor-skeleton__content { + .interface-interface-skeleton__content { background-color: #f1f1f1; } } diff --git a/packages/editor/package.json b/packages/editor/package.json index bd9f025e6dca79..53c8e2a88fb407 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/editor", - "version": "9.12.5", + "version": "9.14.1", "description": "Building blocks for WordPress editors.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -21,7 +21,7 @@ "module": "build-module/index.js", "react-native": "src/index", "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/api-fetch": "file:../api-fetch", "@wordpress/autop": "file:../autop", "@wordpress/blob": "file:../blob", @@ -52,7 +52,7 @@ "@wordpress/wordcount": "file:../wordcount", "classnames": "^2.2.5", "lodash": "^4.17.15", - "memize": "^1.0.5", + "memize": "^1.1.0", "react-autosize-textarea": "^3.0.2", "redux-optimist": "^1.0.0", "refx": "^3.0.0", diff --git a/packages/editor/src/components/autocompleters/index.js b/packages/editor/src/components/autocompleters/index.js index 8b494925b94cce..5cec8914cf8516 100644 --- a/packages/editor/src/components/autocompleters/index.js +++ b/packages/editor/src/components/autocompleters/index.js @@ -1,2 +1 @@ -export { default as blockAutocompleter } from './block'; export { default as userAutocompleter } from './user'; diff --git a/packages/editor/src/components/autocompleters/style.scss b/packages/editor/src/components/autocompleters/style.scss index c48cc9f05d14a6..1d20b34eeb8709 100644 --- a/packages/editor/src/components/autocompleters/style.scss +++ b/packages/editor/src/components/autocompleters/style.scss @@ -1,9 +1,3 @@ -.editor-autocompleters__block { - .block-editor-block-icon { - margin-right: 8px; - } -} - .editor-autocompleters__user { .editor-autocompleters__no-avatar::before { /* stylelint-disable */ diff --git a/packages/editor/src/components/document-outline/style.scss b/packages/editor/src/components/document-outline/style.scss index c02f815eb6f09a..52e1a9e5b91fbd 100644 --- a/packages/editor/src/components/document-outline/style.scss +++ b/packages/editor/src/components/document-outline/style.scss @@ -51,13 +51,17 @@ padding: 2px 5px 2px 1px; color: $dark-gray-800; text-align: left; + border-radius: $radius-block-ui; &:disabled { cursor: default; } &:focus { - @include button-style__focus-active; + box-shadow: 0 0 0 $border-width-focus $theme-color; + + // Windows High Contrast mode will show this outline, but not the box-shadow. + outline: 2px solid transparent; } } diff --git a/packages/editor/src/components/editor-notices/style.scss b/packages/editor/src/components/editor-notices/style.scss index 14ea34748cce53..b9687bc87de866 100644 --- a/packages/editor/src/components/editor-notices/style.scss +++ b/packages/editor/src/components/editor-notices/style.scss @@ -35,4 +35,8 @@ .components-editor-notices__snackbar { width: 100%; + @include break-medium() { + width: fit-content; + width: -moz-fit-content; + } } diff --git a/packages/editor/src/components/entities-saved-states/index.js b/packages/editor/src/components/entities-saved-states/index.js index be2d8a804eb7fe..460823f3bcf856 100644 --- a/packages/editor/src/components/entities-saved-states/index.js +++ b/packages/editor/src/components/entities-saved-states/index.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { some } from 'lodash'; +import { some, groupBy } from 'lodash'; /** * WordPress dependencies @@ -12,48 +12,69 @@ import { useSelect, useDispatch } from '@wordpress/data'; import { useState } from '@wordpress/element'; function EntityRecordState( { record, checked, onChange } ) { - const entity = useSelect( - ( select ) => select( 'core' ).getEntity( record.kind, record.name ), - [ record.kind, record.name ] - ); - return ( <CheckboxControl - label={ - <> - { entity.label } - { !! record.title && ( - <> - { ': ' } - <strong> - { record.title || __( 'Untitled' ) } - </strong> - </> - ) } - </> - } - checked={ ! checked } + label={ <strong>{ record.title || __( 'Untitled' ) }</strong> } + checked={ checked } onChange={ onChange } /> ); } -export default function EntitiesSavedStates( { - isOpen, - onRequestClose, - ignoredForSave = [], -} ) { +function EntityTypeList( { list, unselectedEntities, setUnselectedEntities } ) { + const firstRecord = list[ 0 ]; + const entity = useSelect( + ( select ) => + select( 'core' ).getEntity( firstRecord.kind, firstRecord.name ), + [ firstRecord.kind, firstRecord.name ] + ); + + return ( + <div className="editor-entities-saved-states__entity-type-list"> + <h2>{ entity.label }</h2> + { list.map( ( record ) => { + return ( + <EntityRecordState + key={ record.key || 'site' } + record={ record } + checked={ + ! some( + unselectedEntities, + ( elt ) => + elt.kind === record.kind && + elt.name === record.name && + elt.key === record.key + ) + } + onChange={ ( value ) => + setUnselectedEntities( record, value ) + } + /> + ); + } ) } + </div> + ); +} + +export default function EntitiesSavedStates( { isOpen, onRequestClose } ) { const dirtyEntityRecords = useSelect( ( select ) => select( 'core' ).__experimentalGetDirtyEntityRecords(), [] ); const { saveEditedEntityRecord } = useDispatch( 'core' ); - const [ unsavedEntityRecords, _setUnsavedEntityRecords ] = useState( [] ); - const setUnsavedEntityRecords = ( { kind, name, key }, checked ) => { + // To group entities by type. + const partitionedSavables = Object.values( + groupBy( dirtyEntityRecords, 'name' ) + ); + + // Unchecked entities to be ignored by save function. + const [ unselectedEntities, _setUnselectedEntities ] = useState( [] ); + + const setUnselectedEntities = ( { kind, name, key }, checked ) => { if ( checked ) { - _setUnsavedEntityRecords( - unsavedEntityRecords.filter( + _setUnselectedEntities( + unselectedEntities.filter( ( elt ) => elt.kind !== kind || elt.name !== name || @@ -61,17 +82,18 @@ export default function EntitiesSavedStates( { ) ); } else { - _setUnsavedEntityRecords( [ - ...unsavedEntityRecords, + _setUnselectedEntities( [ + ...unselectedEntities, { kind, name, key }, ] ); } }; + const saveCheckedEntities = () => { const entitiesToSave = dirtyEntityRecords.filter( ( { kind, name, key } ) => { return ! some( - ignoredForSave.concat( unsavedEntityRecords ), + unselectedEntities, ( elt ) => elt.kind === kind && elt.name === name && @@ -86,6 +108,7 @@ export default function EntitiesSavedStates( { onRequestClose( entitiesToSave ); }; + return ( isOpen && ( <Modal @@ -93,23 +116,13 @@ export default function EntitiesSavedStates( { onRequestClose={ () => onRequestClose() } contentLabel={ __( 'Select items to save.' ) } > - { dirtyEntityRecords.map( ( record ) => { + { partitionedSavables.map( ( list ) => { return ( - <EntityRecordState - key={ record.key } - record={ record } - checked={ - ! some( - unsavedEntityRecords, - ( elt ) => - elt.kind === record.kind && - elt.name === record.name && - elt.key === record.key - ) - } - onChange={ ( value ) => - setUnsavedEntityRecords( record, value ) - } + <EntityTypeList + key={ list[ 0 ].name } + list={ list } + unselectedEntities={ unselectedEntities } + setUnselectedEntities={ setUnselectedEntities } /> ); } ) } @@ -118,7 +131,7 @@ export default function EntitiesSavedStates( { isPrimary disabled={ dirtyEntityRecords.length - - unsavedEntityRecords.length === + unselectedEntities.length === 0 } onClick={ saveCheckedEntities } diff --git a/packages/editor/src/components/entities-saved-states/style.scss b/packages/editor/src/components/entities-saved-states/style.scss index 6751b3ef2673b8..6a04c3db879c89 100644 --- a/packages/editor/src/components/entities-saved-states/style.scss +++ b/packages/editor/src/components/entities-saved-states/style.scss @@ -3,3 +3,9 @@ margin-left: auto; margin-right: 0; } +.editor-entities-saved-states__entity-type-list { + h2 { + font-size: 18px; + margin: 20px 0 10px; + } +} diff --git a/packages/editor/src/components/post-last-revision/index.js b/packages/editor/src/components/post-last-revision/index.js index b24f0f3ac0c1cc..643b6c1a4700a6 100644 --- a/packages/editor/src/components/post-last-revision/index.js +++ b/packages/editor/src/components/post-last-revision/index.js @@ -24,6 +24,7 @@ function LastRevision( { lastRevisionId, revisionsCount } ) { icon={ backup } > { sprintf( + /* translators: %d: number of revisions */ _n( '%d Revision', '%d Revisions', revisionsCount ), revisionsCount ) } diff --git a/packages/editor/src/components/post-last-revision/style.scss b/packages/editor/src/components/post-last-revision/style.scss index 1976ec65496006..d9fd35f16edb5c 100644 --- a/packages/editor/src/components/post-last-revision/style.scss +++ b/packages/editor/src/components/post-last-revision/style.scss @@ -7,19 +7,17 @@ } } -// Needs specificity -.components-button:not(:disabled):not([aria-disabled="true"]).editor-post-last-revision__title { +.components-button.editor-post-last-revision__title { height: auto; &:hover, &:active { // Override the default button hover style - background: $light-gray-200 !important; - border: none !important; - box-shadow: none !important; + background: $light-gray-200; } &:focus { - @include menu-style__focus; + box-shadow: inset 0 0 0 $border-width-focus $theme-color; + border-radius: 0; } } diff --git a/packages/editor/src/components/post-permalink/editor.js b/packages/editor/src/components/post-permalink/editor.js deleted file mode 100644 index a09ee66ed984a8..00000000000000 --- a/packages/editor/src/components/post-permalink/editor.js +++ /dev/null @@ -1,102 +0,0 @@ -/** - * WordPress dependencies - */ -import { withDispatch, withSelect } from '@wordpress/data'; -import { Component } from '@wordpress/element'; -import { __ } from '@wordpress/i18n'; -import { Button } from '@wordpress/components'; -import { compose } from '@wordpress/compose'; - -/** - * Internal dependencies - */ -import { cleanForSlug } from '../../utils/url'; - -class PostPermalinkEditor extends Component { - constructor( { permalinkParts, slug } ) { - super( ...arguments ); - - this.state = { - editedPostName: slug || permalinkParts.postName, - }; - - this.onSavePermalink = this.onSavePermalink.bind( this ); - } - - onSavePermalink( event ) { - const postName = cleanForSlug( this.state.editedPostName ); - - event.preventDefault(); - - this.props.onSave(); - - if ( postName === this.props.postName ) { - return; - } - - this.props.editPost( { - slug: postName, - } ); - - this.setState( { - editedPostName: postName, - } ); - } - - render() { - const { prefix, suffix } = this.props.permalinkParts; - const { editedPostName } = this.state; - - /* eslint-disable jsx-a11y/no-autofocus */ - // Autofocus is allowed here, as this mini-UI is only loaded when the user clicks to open it. - return ( - <form - className="editor-post-permalink-editor" - onSubmit={ this.onSavePermalink } - > - <span className="editor-post-permalink__editor-container"> - <span className="editor-post-permalink-editor__prefix"> - { prefix } - </span> - <input - className="editor-post-permalink-editor__edit" - aria-label={ __( 'Edit post permalink' ) } - value={ editedPostName } - onChange={ ( event ) => - this.setState( { - editedPostName: event.target.value, - } ) - } - type="text" - autoFocus - /> - <span className="editor-post-permalink-editor__suffix"> - { suffix } - </span> - &lrm; - </span> - <Button - className="editor-post-permalink-editor__save" - isSecondary - onClick={ this.onSavePermalink } - > - { __( 'Save' ) } - </Button> - </form> - ); - /* eslint-enable jsx-a11y/no-autofocus */ - } -} - -export default compose( [ - withSelect( ( select ) => { - const { getPermalinkParts } = select( 'core/editor' ); - return { - permalinkParts: getPermalinkParts(), - }; - } ), - withDispatch( ( dispatch ) => { - const { editPost } = dispatch( 'core/editor' ); - return { editPost }; - } ), -] )( PostPermalinkEditor ); diff --git a/packages/editor/src/components/post-permalink/index.js b/packages/editor/src/components/post-permalink/index.js deleted file mode 100644 index 1facb8432f41a6..00000000000000 --- a/packages/editor/src/components/post-permalink/index.js +++ /dev/null @@ -1,176 +0,0 @@ -/** - * External dependencies - */ -import classnames from 'classnames'; -import { get } from 'lodash'; - -/** - * WordPress dependencies - */ -import { withDispatch, withSelect } from '@wordpress/data'; -import { Component } from '@wordpress/element'; -import { __ } from '@wordpress/i18n'; -import { compose } from '@wordpress/compose'; -import { ClipboardButton, Button, ExternalLink } from '@wordpress/components'; -import { safeDecodeURI, safeDecodeURIComponent } from '@wordpress/url'; -import { link as linkIcon } from '@wordpress/icons'; - -/** - * Internal dependencies - */ -import PostPermalinkEditor from './editor.js'; - -class PostPermalink extends Component { - constructor() { - super( ...arguments ); - - this.addVisibilityCheck = this.addVisibilityCheck.bind( this ); - this.onVisibilityChange = this.onVisibilityChange.bind( this ); - - this.state = { - isCopied: false, - isEditingPermalink: false, - }; - } - - addVisibilityCheck() { - window.addEventListener( 'visibilitychange', this.onVisibilityChange ); - } - - onVisibilityChange() { - const { isEditable, refreshPost } = this.props; - // If the user just returned after having clicked the "Change Permalinks" button, - // fetch a new copy of the post from the server, just in case they enabled permalinks. - if ( ! isEditable && 'visible' === document.visibilityState ) { - refreshPost(); - } - } - - componentDidUpdate( prevProps, prevState ) { - // If we've just stopped editing the permalink, focus on the new permalink. - if ( prevState.isEditingPermalink && ! this.state.isEditingPermalink ) { - this.linkElement.focus(); - } - } - - componentWillUnmount() { - window.removeEventListener( - 'visibilitychange', - this.addVisibilityCheck - ); - } - - render() { - const { - isEditable, - isNew, - isPublished, - isViewable, - permalinkParts, - postLink, - postSlug, - } = this.props; - - if ( isNew || ! isViewable || ! permalinkParts || ! postLink ) { - return null; - } - - const { isCopied, isEditingPermalink } = this.state; - const ariaLabel = isCopied - ? __( 'Permalink copied' ) - : __( 'Copy the permalink' ); - - const { prefix, suffix } = permalinkParts; - const samplePermalink = isEditable - ? prefix + postSlug + suffix - : prefix; - - return ( - <div className="editor-post-permalink"> - <ClipboardButton - className={ classnames( 'editor-post-permalink__copy', { - 'is-copied': isCopied, - } ) } - text={ samplePermalink } - label={ ariaLabel } - onCopy={ () => this.setState( { isCopied: true } ) } - aria-disabled={ isCopied } - icon={ linkIcon } - /> - - <span className="editor-post-permalink__label"> - { __( 'Permalink:' ) } - </span> - - { ! isEditingPermalink && ( - <ExternalLink - className="editor-post-permalink__link" - href={ ! isPublished ? postLink : samplePermalink } - target="_blank" - ref={ ( linkElement ) => - ( this.linkElement = linkElement ) - } - > - { safeDecodeURI( samplePermalink ) } - &lrm; - </ExternalLink> - ) } - - { isEditingPermalink && ( - <PostPermalinkEditor - slug={ postSlug } - onSave={ () => - this.setState( { isEditingPermalink: false } ) - } - /> - ) } - - { isEditable && ! isEditingPermalink && ( - <Button - className="editor-post-permalink__edit" - isSecondary - onClick={ () => - this.setState( { isEditingPermalink: true } ) - } - > - { __( 'Edit' ) } - </Button> - ) } - </div> - ); - } -} - -export default compose( [ - withSelect( ( select ) => { - const { - isEditedPostNew, - isPermalinkEditable, - getCurrentPost, - getPermalinkParts, - getEditedPostAttribute, - isCurrentPostPublished, - getEditedPostSlug, - } = select( 'core/editor' ); - const { getPostType } = select( 'core' ); - - const { link } = getCurrentPost(); - - const postTypeName = getEditedPostAttribute( 'type' ); - const postType = getPostType( postTypeName ); - - return { - isNew: isEditedPostNew(), - postLink: link, - permalinkParts: getPermalinkParts(), - postSlug: safeDecodeURIComponent( getEditedPostSlug() ), - isEditable: isPermalinkEditable(), - isPublished: isCurrentPostPublished(), - isViewable: get( postType, [ 'viewable' ], false ), - }; - } ), - withDispatch( ( dispatch ) => { - const { refreshPost } = dispatch( 'core/editor' ); - return { refreshPost }; - } ), -] )( PostPermalink ); diff --git a/packages/editor/src/components/post-permalink/style.scss b/packages/editor/src/components/post-permalink/style.scss deleted file mode 100644 index 241250696123cf..00000000000000 --- a/packages/editor/src/components/post-permalink/style.scss +++ /dev/null @@ -1,140 +0,0 @@ -.editor-post-permalink { - display: inline-flex; - align-items: center; - flex-wrap: wrap; - padding: $grid-unit-10 $grid-unit-10 0; - font-family: $default-font; - font-size: $default-font-size; - white-space: nowrap; - background-clip: padding-box; - - // Block UI appearance. - border: $border-width solid $dark-gray-primary; - border-radius: $radius-block-ui; - background-color: $white; - - // Put toolbar snugly to edge on mobile. - margin-left: -$block-padding - $border-width; // This hides the border off the edge of the screen. - margin-right: -$block-padding - $border-width; - @include break-mobile() { - padding: $grid-unit-05; - } - @include break-small() { - margin-left: -$border-width; - margin-right: -$border-width; - } - - // Increase specificity to override margins set on label element. - &.editor-post-permalink > * { - margin-bottom: $grid-unit-10; - - @include break-mobile() { - margin-bottom: 0; - } - } - - // Prevent button shrinking in IE11 when other items have a 100% flex basis. - // This should be safe to apply in all browsers because we don't want these - // buttons to shrink anyway. - button { - flex-shrink: 0; - } -} - -.editor-post-permalink__copy { - border-radius: 4px; - padding: 6px; -} - -.editor-post-permalink__copy.is-copied { - opacity: 0.3; -} - -.editor-post-permalink__label { - margin: 0 10px 0 5px; - font-weight: 600; -} - -.editor-post-permalink__link { - color: $dark-gray-200; - text-decoration: underline; - margin-right: 10px; - flex-grow: 1; - overflow: hidden; - position: relative; - white-space: nowrap; - text-align: left; -} - -.editor-post-permalink-editor { - width: 100%; - min-width: 20%; - display: inline-flex; - align-items: center; - - .editor-post-permalink__editor-container { - flex: 0 1 100%; - display: flex; - overflow: hidden; // This enables serious flex shrinking. - padding: $border-width 0; // Necessary for the overflow to not crop the focus style. - - .editor-post-permalink-editor__prefix { - flex: 1 1 auto; - - @include break-small { - flex: 1 0 auto; - } - } - - .editor-post-permalink-editor__edit { - flex: 1 1 100%; - } - } - - // Higher specificity required to override core margin styles. - .editor-post-permalink-editor__save { - margin-left: auto; - } -} - -.editor-post-permalink-editor__prefix { - color: $dark-gray-300; - min-width: 20%; - overflow: hidden; - position: relative; - white-space: nowrap; - text-overflow: ellipsis; -} - -.editor-post-permalink input[type="text"].editor-post-permalink-editor__edit { - // Input fields are created with inherent widths. - // By supplying both a (any) width and a min-width, we allow it to scale in a flex container. - min-width: 10%; - width: 100%; - margin: 0 3px; - padding: 2px 4px; -} - -.editor-post-permalink-editor__suffix { - color: $dark-gray-300; - margin-right: 6px; - flex: 0 0 0%; -} - -.editor-post-permalink-editor__prefix { - text-align: left; -} - -/* rtl:begin:ignore */ -.editor-post-permalink__link { - text-align: left; -} -.editor-post-permalink__editor-container, -.editor-post-permalink__link { - direction: ltr; -} -.editor-post-permalink__link::after { - @include long-content-fade($direction:right, $size: 20%, $edge: 0); -} -/* rtl:end:ignore */ - diff --git a/packages/editor/src/components/post-publish-button/index.js b/packages/editor/src/components/post-publish-button/index.js index 6405ae571a3db8..c2383f52c19afb 100644 --- a/packages/editor/src/components/post-publish-button/index.js +++ b/packages/editor/src/components/post-publish-button/index.js @@ -3,7 +3,6 @@ */ import { noop, get, some } from 'lodash'; import classnames from 'classnames'; -import memoize from 'memize'; /** * WordPress dependencies @@ -33,12 +32,6 @@ export class PostPublishButton extends Component { this.state = { entitiesSavedStatesCallback: false, }; - this.createIgnoredForSave = memoize( - ( postType, postId ) => [ - { kind: 'postType', name: postType, key: postId }, - ], - { maxSize: 1 } - ); } componentDidMount() { if ( this.props.focusOnMount ) { @@ -102,8 +95,6 @@ export class PostPublishButton extends Component { onToggle, visibility, hasNonPostEntityChanges, - postType, - postId, } = this.props; const { entitiesSavedStatesCallback } = this.state; @@ -182,10 +173,6 @@ export class PostPublishButton extends Component { <EntitiesSavedStates isOpen={ Boolean( entitiesSavedStatesCallback ) } onRequestClose={ this.closeEntitiesSavedStates } - ignoredForSave={ this.createIgnoredForSave( - postType, - postId - ) } /> <Button ref={ this.buttonNode } diff --git a/packages/editor/src/components/post-publish-panel/index.js b/packages/editor/src/components/post-publish-panel/index.js index b3621483495822..232d23f5cc0a9d 100644 --- a/packages/editor/src/components/post-publish-panel/index.js +++ b/packages/editor/src/components/post-publish-panel/index.js @@ -95,7 +95,6 @@ export class PostPublishPanel extends Component { </div> ) } <Button - aria-expanded={ true } onClick={ onClose } icon={ close } label={ __( 'Close panel' ) } diff --git a/packages/editor/src/components/post-publish-panel/maybe-post-format-panel.js b/packages/editor/src/components/post-publish-panel/maybe-post-format-panel.js index fede6a0a33186d..5d173e4f3c6807 100644 --- a/packages/editor/src/components/post-publish-panel/maybe-post-format-panel.js +++ b/packages/editor/src/components/post-publish-panel/maybe-post-format-panel.js @@ -46,6 +46,7 @@ const PostFormatPanel = ( { suggestion, onUpdatePostFormat } ) => { onUpdatePostFormat={ onUpdatePostFormat } suggestedPostFormat={ suggestion.id } suggestionText={ sprintf( + /* translators: %s: post format */ __( 'Apply the "%1$s" format.' ), suggestion.caption ) } diff --git a/packages/editor/src/components/post-publish-panel/postpublish.js b/packages/editor/src/components/post-publish-panel/postpublish.js index 21ea2144d052f0..c7aa69bddb20cd 100644 --- a/packages/editor/src/components/post-publish-panel/postpublish.js +++ b/packages/editor/src/components/post-publish-panel/postpublish.js @@ -23,6 +23,26 @@ import { decodeEntities } from '@wordpress/html-entities'; */ import PostScheduleLabel from '../post-schedule/label'; +const POSTNAME = '%postname%'; + +/** + * Returns URL for a future post. + * + * @param {Object} post Post object. + * + * @return {string} PostPublish URL. + */ + +const getFuturePostUrl = ( post ) => { + const { slug } = post; + + if ( post.permalink_template.includes( POSTNAME ) ) { + return post.permalink_template.replace( POSTNAME, slug ); + } + + return post.permalink_template; +}; + class PostPublishPanelPostpublish extends Component { constructor() { super( ...arguments ); @@ -65,6 +85,8 @@ class PostPublishPanelPostpublish extends Component { const { children, isScheduled, post, postType } = this.props; const postLabel = get( postType, [ 'labels', 'singular_name' ] ); const viewPostLabel = get( postType, [ 'labels', 'view_item' ] ); + const link = + post.status === 'future' ? getFuturePostUrl( post ) : post.link; const postPublishNonLinkHeader = isScheduled ? ( <> @@ -78,7 +100,7 @@ class PostPublishPanelPostpublish extends Component { return ( <div className="post-publish-panel__postpublish"> <PanelBody className="post-publish-panel__postpublish-header"> - <a ref={ this.postLink } href={ post.link }> + <a ref={ this.postLink } href={ link }> { decodeEntities( post.title ) || __( '(no title)' ) } </a>{ ' ' } { postPublishNonLinkHeader } @@ -95,19 +117,19 @@ class PostPublishPanelPostpublish extends Component { __( '%s address' ), postLabel ) } - value={ safeDecodeURIComponent( post.link ) } + value={ safeDecodeURIComponent( link ) } onFocus={ this.onSelectInput } /> <div className="post-publish-panel__postpublish-buttons"> { ! isScheduled && ( - <Button isSecondary href={ post.link }> + <Button isSecondary href={ link }> { viewPostLabel } </Button> ) } <ClipboardButton isSecondary - text={ post.link } + text={ link } onCopy={ this.onCopy } > { this.state.showCopyConfirmation diff --git a/packages/editor/src/components/post-publish-panel/style.scss b/packages/editor/src/components/post-publish-panel/style.scss index 254e67e59522c0..93904e14fdbbcb 100644 --- a/packages/editor/src/components/post-publish-panel/style.scss +++ b/packages/editor/src/components/post-publish-panel/style.scss @@ -14,9 +14,9 @@ .editor-post-publish-panel__header { background: $white; - padding-left: 8px; - padding-right: 8px; - height: $header-height; + padding-left: $grid-unit-10; + padding-right: $grid-unit-10; + height: $header-height + $border-width; border-bottom: $border-width solid $light-gray-500; display: flex; align-items: center; @@ -24,7 +24,7 @@ .components-button.has-icon { position: absolute; - right: 8px; + right: $grid-unit-10; } } diff --git a/packages/editor/src/components/post-publish-panel/test/__snapshots__/index.js.snap b/packages/editor/src/components/post-publish-panel/test/__snapshots__/index.js.snap index 39124b699590bb..e31518a8c63542 100644 --- a/packages/editor/src/components/post-publish-panel/test/__snapshots__/index.js.snap +++ b/packages/editor/src/components/post-publish-panel/test/__snapshots__/index.js.snap @@ -13,7 +13,6 @@ exports[`PostPublishPanel should render the post-publish panel if the post is pu Published </div> <ForwardRef(Button) - aria-expanded={true} icon={ <SVG viewBox="0 0 24 24" @@ -57,7 +56,6 @@ exports[`PostPublishPanel should render the post-publish panel if the post is sc Scheduled </div> <ForwardRef(Button) - aria-expanded={true} icon={ <SVG viewBox="0 0 24 24" @@ -104,7 +102,6 @@ exports[`PostPublishPanel should render the pre-publish panel if post status is /> </div> <ForwardRef(Button) - aria-expanded={true} icon={ <SVG viewBox="0 0 24 24" @@ -149,7 +146,6 @@ exports[`PostPublishPanel should render the pre-publish panel if the post is not /> </div> <ForwardRef(Button) - aria-expanded={true} icon={ <SVG viewBox="0 0 24 24" @@ -194,7 +190,6 @@ exports[`PostPublishPanel should render the spinner if the post is being saved 1 /> </div> <ForwardRef(Button) - aria-expanded={true} icon={ <SVG viewBox="0 0 24 24" diff --git a/packages/editor/src/components/post-taxonomies/flat-term-selector.js b/packages/editor/src/components/post-taxonomies/flat-term-selector.js index 299245a5e45aad..c6dd5af6db8530 100644 --- a/packages/editor/src/components/post-taxonomies/flat-term-selector.js +++ b/packages/editor/src/components/post-taxonomies/flat-term-selector.js @@ -245,14 +245,17 @@ class FlatTermSelector extends Component { slug === 'post_tag' ? __( 'Tag' ) : __( 'Term' ) ); const termAddedLabel = sprintf( + /* translators: %s: term name. */ _x( '%s added', 'term' ), singularName ); const termRemovedLabel = sprintf( + /* translators: %s: term name. */ _x( '%s removed', 'term' ), singularName ); const removeTermLabel = sprintf( + /* translators: %s: term name. */ _x( 'Remove %s', 'term' ), singularName ); diff --git a/packages/editor/src/components/post-taxonomies/hierarchical-term-selector.js b/packages/editor/src/components/post-taxonomies/hierarchical-term-selector.js index c8897753492f13..234b5f25e8f6ac 100644 --- a/packages/editor/src/components/post-taxonomies/hierarchical-term-selector.js +++ b/packages/editor/src/components/post-taxonomies/hierarchical-term-selector.js @@ -171,6 +171,7 @@ class HierarchicalTermSelector extends Component { ? this.state.availableTerms : [ term, ...this.state.availableTerms ]; const termAddedMessage = sprintf( + /* translators: %s: taxonomy name */ _x( '%s added', 'term' ), get( this.props.taxonomy, @@ -319,6 +320,7 @@ class HierarchicalTermSelector extends Component { const resultCount = getResultCount( filteredTermsTree ); const resultsFoundMessage = sprintf( + /* translators: %d: number of results */ _n( '%d result found.', '%d results found.', resultCount ), resultCount ); diff --git a/packages/editor/src/components/post-text-editor/style.scss b/packages/editor/src/components/post-text-editor/style.scss index 4f5381dc02fd58..8041d05031dd1c 100644 --- a/packages/editor/src/components/post-text-editor/style.scss +++ b/packages/editor/src/components/post-text-editor/style.scss @@ -1,14 +1,16 @@ -.editor-post-text-editor { - border: $border-width solid $light-gray-500 !important; +.edit-post-text-editor__body textarea.editor-post-text-editor { + border: $border-width solid $light-gray-secondary; display: block; - margin: 0 0 2em; + margin: 0; width: 100%; box-shadow: none; resize: none; overflow: hidden; - font-family: $editor-html-font !important; + font-family: $editor-html-font; line-height: 150%; - border-radius: 0 !important; + border-radius: 0; + padding: $grid-unit-20; + min-height: 200px; /* Fonts smaller than 16px causes mobile safari to zoom. */ font-size: $mobile-text-min-font-size !important; @@ -16,56 +18,11 @@ font-size: $text-editor-font-size !important; } - &:hover, &:focus { - border: $border-width solid $dark-gray-primary !important; - box-shadow: none !important; - // Emulate the effect used on the post title. - outline-offset: -2px !important; - } -} - -.editor-post-text-editor__toolbar { - display: flex; - flex-direction: row; - flex-wrap: wrap; - - button { - height: 30px; - background: none; - padding: 0 8px; - margin: 3px 4px; - text-align: center; - cursor: pointer; - font-family: $editor-html-font; - color: $dark-gray-500; - border: $border-width solid transparent; + border: $border-width solid $dark-gray-primary; + box-shadow: none; - &:first-child { - margin-left: 0; - } - - &:hover, - &:focus { - outline: none; - border: $border-width solid $dark-gray-500; - } + // Elevate the z-index on focus so the focus style is uncropped. + position: relative; } } - -.editor-post-text-editor__bold { - font-weight: 600; -} - -.editor-post-text-editor__italic { - font-style: italic; -} - -.editor-post-text-editor__link { - text-decoration: underline; - color: theme(primary); -} - -.editor-post-text-editor__del { - text-decoration: line-through; -} diff --git a/packages/editor/src/components/post-title/index.js b/packages/editor/src/components/post-title/index.js index 3a5f17a8f68536..ccc5eb1077fa32 100644 --- a/packages/editor/src/components/post-title/index.js +++ b/packages/editor/src/components/post-title/index.js @@ -3,7 +3,6 @@ */ import Textarea from 'react-autosize-textarea'; import classnames from 'classnames'; -import { get } from 'lodash'; /** * WordPress dependencies @@ -13,13 +12,12 @@ import { Component } from '@wordpress/element'; import { decodeEntities } from '@wordpress/html-entities'; import { ENTER } from '@wordpress/keycodes'; import { withSelect, withDispatch } from '@wordpress/data'; -import { withFocusOutside, VisuallyHidden } from '@wordpress/components'; +import { VisuallyHidden } from '@wordpress/components'; import { withInstanceId, compose } from '@wordpress/compose'; /** * Internal dependencies */ -import PostPermalink from '../post-permalink'; import PostTypeSupportCheck from '../post-type-support-check'; /** @@ -41,10 +39,6 @@ class PostTitle extends Component { }; } - handleFocusOutside() { - this.onUnselect(); - } - onSelect() { this.setState( { isSelected: true } ); this.props.clearSelectedBlock(); @@ -71,7 +65,6 @@ class PostTitle extends Component { hasFixedToolbar, isCleanNewPost, isFocusMode, - isPostTypeViewable, instanceId, placeholder, title, @@ -79,53 +72,50 @@ class PostTitle extends Component { const { isSelected } = this.state; // The wp-block className is important for editor styles. - const className = classnames( 'wp-block editor-post-title__block', { - 'is-selected': isSelected, - 'is-focus-mode': isFocusMode, - 'has-fixed-toolbar': hasFixedToolbar, - } ); + // This same block is used in both the visual and the code editor. + const className = classnames( + 'wp-block editor-post-title editor-post-title__block', + { + 'is-selected': isSelected, + 'is-focus-mode': isFocusMode, + 'has-fixed-toolbar': hasFixedToolbar, + } + ); const decodedPlaceholder = decodeEntities( placeholder ); return ( <PostTypeSupportCheck supportKeys="title"> - <div className="editor-post-title"> - <div className={ className }> - <div> - <VisuallyHidden - as="label" - htmlFor={ `post-title-${ instanceId }` } - > - { decodedPlaceholder || __( 'Add title' ) } - </VisuallyHidden> - <Textarea - id={ `post-title-${ instanceId }` } - className="editor-post-title__input" - value={ title } - onChange={ this.onChange } - placeholder={ - decodedPlaceholder || __( 'Add title' ) - } - onFocus={ this.onSelect } - onKeyDown={ this.onKeyDown } - onKeyPress={ this.onUnselect } - /* - Only autofocus the title when the post is entirely empty. - This should only happen for a new post, which means we - focus the title on new post so the author can start typing - right away, without needing to click anything. - */ - /* eslint-disable jsx-a11y/no-autofocus */ - autoFocus={ - document.body === document.activeElement && - isCleanNewPost - } - /* eslint-enable jsx-a11y/no-autofocus */ - /> - </div> - { isSelected && isPostTypeViewable && ( - <PostPermalink /> - ) } - </div> + <div className={ className }> + <VisuallyHidden + as="label" + htmlFor={ `post-title-${ instanceId }` } + > + { decodedPlaceholder || __( 'Add title' ) } + </VisuallyHidden> + <Textarea + id={ `post-title-${ instanceId }` } + className="editor-post-title__input" + value={ title } + onChange={ this.onChange } + placeholder={ decodedPlaceholder || __( 'Add title' ) } + onFocus={ this.onSelect } + onBlur={ this.onUnselect } + onKeyDown={ this.onKeyDown } + onKeyPress={ this.onUnselect } + /* + Only autofocus the title when the post is entirely empty. + This should only happen for a new post, which means we + focus the title on new post so the author can start typing + right away, without needing to click anything. + */ + /* eslint-disable jsx-a11y/no-autofocus */ + autoFocus={ + ( document.body === document.activeElement || + ! document.activeElement ) && + isCleanNewPost + } + /* eslint-enable jsx-a11y/no-autofocus */ + /> </div> </PostTypeSupportCheck> ); @@ -135,14 +125,11 @@ class PostTitle extends Component { const applyWithSelect = withSelect( ( select ) => { const { getEditedPostAttribute, isCleanNewPost } = select( 'core/editor' ); const { getSettings } = select( 'core/block-editor' ); - const { getPostType } = select( 'core' ); - const postType = getPostType( getEditedPostAttribute( 'type' ) ); const { titlePlaceholder, focusMode, hasFixedToolbar } = getSettings(); return { isCleanNewPost: isCleanNewPost(), title: getEditedPostAttribute( 'title' ), - isPostTypeViewable: get( postType, [ 'viewable' ], false ), placeholder: titlePlaceholder, isFocusMode: focusMode, hasFixedToolbar, @@ -169,6 +156,5 @@ const applyWithDispatch = withDispatch( ( dispatch ) => { export default compose( applyWithSelect, applyWithDispatch, - withInstanceId, - withFocusOutside + withInstanceId )( PostTitle ); diff --git a/packages/editor/src/components/post-title/style.native.scss b/packages/editor/src/components/post-title/style.native.scss index 375d423a6cffd4..623ee573a92c79 100644 --- a/packages/editor/src/components/post-title/style.native.scss +++ b/packages/editor/src/components/post-title/style.native.scss @@ -8,6 +8,6 @@ } .dimmed { - opacity: 0.2; + opacity: $dimmed-opacity; } diff --git a/packages/editor/src/components/post-title/style.scss b/packages/editor/src/components/post-title/style.scss index 8760c20f196ace..214f68d861c1cc 100644 --- a/packages/editor/src/components/post-title/style.scss +++ b/packages/editor/src/components/post-title/style.scss @@ -1,11 +1,5 @@ -.editor-post-title__block { +.editor-post-title { position: relative; - padding: 5px 0; - font-size: $editor-font-size; - - @include break-small() { - padding: 5px $block-side-ui-clearance; - } .editor-post-title__input { display: block; @@ -13,14 +7,16 @@ margin: 0; box-shadow: none; background: transparent; - font-family: $editor-font; - line-height: $default-line-height; - color: $dark-gray-900; transition: border 0.1s ease-out, box-shadow 0.1s linear; @include reduce-motion("transition"); - padding: #{ $block-padding + 5px } $block-padding; + padding: #{ $block-padding + 5px } 0; word-break: keep-all; + // Inherit the styles set by the theme. + font-family: inherit; + line-height: inherit; + color: inherit; + // Stack borders on mobile. border: $border-width solid transparent; border-left-width: 0; @@ -36,7 +32,7 @@ // Match h1 heading. font-size: 2.44em; - font-weight: 600; + font-weight: bold; // Large text needs a 3:1 contrast ratio. &::-webkit-input-placeholder { @@ -68,24 +64,3 @@ } } } - -.editor-post-title .editor-post-permalink { - font-size: $default-font-size; - color: $dark-gray-900; - height: auto; - position: relative; - top: -2px; - width: 100%; - - @include break-mobile() { - position: absolute; - top: -$button-size + $border-width + $border-width + 1px; // Shift this element upward the same height as the block toolbar, minus the border size - right: 0; - flex-wrap: nowrap; - width: auto; - } - @include break-small() { - left: $block-side-ui-clearance; - right: $block-side-ui-clearance; - } -} diff --git a/packages/editor/src/components/provider/index.js b/packages/editor/src/components/provider/index.js index 69a2dbbd958892..1d2326ef58f59f 100644 --- a/packages/editor/src/components/provider/index.js +++ b/packages/editor/src/components/provider/index.js @@ -12,7 +12,11 @@ import { Component } from '@wordpress/element'; import { withDispatch, withSelect } from '@wordpress/data'; import { __ } from '@wordpress/i18n'; import { EntityProvider } from '@wordpress/core-data'; -import { BlockEditorProvider, transformStyles } from '@wordpress/block-editor'; +import { + BlockEditorProvider, + BlockContextProvider, + __unstableEditorStyles as EditorStyles, +} from '@wordpress/block-editor'; import apiFetch from '@wordpress/api-fetch'; import { addQueryArgs } from '@wordpress/url'; import { decodeEntities } from '@wordpress/html-entities'; @@ -50,6 +54,10 @@ class EditorProvider extends Component { maxSize: 1, } ); + this.getDefaultBlockContext = memize( this.getDefaultBlockContext, { + maxSize: 1, + } ); + // Assume that we don't need to initialize in the case of an error recovery. if ( props.recovery ) { return; @@ -114,12 +122,15 @@ class EditorProvider extends Component { 'templateLock', 'titlePlaceholder', 'onUpdateDefaultBlockStyles', + '__experimentalDisableCustomUnits', '__experimentalEnableLegacyWidgetBlock', '__experimentalBlockDirectory', '__experimentalEnableFullSiteEditing', '__experimentalEnableFullSiteEditingDemo', '__experimentalGlobalStylesUserEntityId', '__experimentalGlobalStylesBase', + '__experimentalDisableCustomLineHeight', + '__experimentalBlockPatterns', 'gradients', ] ), mediaUpload: hasUploadPermissions ? mediaUpload : undefined, @@ -132,25 +143,12 @@ class EditorProvider extends Component { }; } + getDefaultBlockContext( postId, postType ) { + return { postId, postType }; + } + componentDidMount() { this.props.updateEditorSettings( this.props.settings ); - - if ( ! this.props.settings.styles ) { - return; - } - - const updatedStyles = transformStyles( - this.props.settings.styles, - '.editor-styles-wrapper' - ); - - map( updatedStyles, ( updatedCSS ) => { - if ( updatedCSS ) { - const node = document.createElement( 'style' ); - node.innerHTML = updatedCSS; - document.body.appendChild( node ); - } - } ); } componentDidUpdate( prevProps ) { @@ -196,28 +194,38 @@ class EditorProvider extends Component { isPostTitleSelected ); + const defaultBlockContext = this.getDefaultBlockContext( + post.id, + post.type + ); + return ( - <EntityProvider kind="root" type="site"> - <EntityProvider - kind="postType" - type={ post.type } - id={ post.id } - > - <BlockEditorProvider - value={ blocks } - onInput={ resetEditorBlocksWithoutUndoLevel } - onChange={ resetEditorBlocks } - selectionStart={ selectionStart } - selectionEnd={ selectionEnd } - settings={ editorSettings } - useSubRegistry={ false } + <> + <EditorStyles styles={ settings.styles } /> + <EntityProvider kind="root" type="site"> + <EntityProvider + kind="postType" + type={ post.type } + id={ post.id } > - { children } - <ReusableBlocksButtons /> - <ConvertToGroupButtons /> - </BlockEditorProvider> + <BlockContextProvider value={ defaultBlockContext }> + <BlockEditorProvider + value={ blocks } + onInput={ resetEditorBlocksWithoutUndoLevel } + onChange={ resetEditorBlocks } + selectionStart={ selectionStart } + selectionEnd={ selectionEnd } + settings={ editorSettings } + useSubRegistry={ false } + > + { children } + <ReusableBlocksButtons /> + <ConvertToGroupButtons /> + </BlockEditorProvider> + </BlockContextProvider> + </EntityProvider> </EntityProvider> - </EntityProvider> + </> ); } } diff --git a/packages/editor/src/components/reusable-blocks-buttons/reusable-block-delete-button.js b/packages/editor/src/components/reusable-blocks-buttons/reusable-block-delete-button.js index f2a9664c640800..7f5e29f009d3f5 100644 --- a/packages/editor/src/components/reusable-blocks-buttons/reusable-block-delete-button.js +++ b/packages/editor/src/components/reusable-blocks-buttons/reusable-block-delete-button.js @@ -69,6 +69,7 @@ export default compose( [ // TODO: Make this a <Confirm /> component or similar // eslint-disable-next-line no-alert const hasConfirmed = window.confirm( + // eslint-disable-next-line @wordpress/i18n-no-collapsible-whitespace __( 'Are you sure you want to delete this Reusable Block?\n\n' + 'It will be permanently removed from all posts and pages that use it.' diff --git a/packages/editor/src/components/table-of-contents/style.scss b/packages/editor/src/components/table-of-contents/style.scss index b7a20dc2a3c3e1..968f69a653764b 100644 --- a/packages/editor/src/components/table-of-contents/style.scss +++ b/packages/editor/src/components/table-of-contents/style.scss @@ -21,9 +21,15 @@ } } -.table-of-contents__wrapper:focus { - @include square-style__focus(); - outline-offset: $grid-unit-10; +.table-of-contents__wrapper:focus::before { + content: ""; + display: block; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + box-shadow: inset 0 0 0 $border-width-focus $theme-color; } .table-of-contents__counts { diff --git a/packages/editor/src/editor-styles.scss b/packages/editor/src/editor-styles.scss index d7316552288953..f8eee44a116938 100644 --- a/packages/editor/src/editor-styles.scss +++ b/packages/editor/src/editor-styles.scss @@ -144,3 +144,17 @@ ol ul { max-width: 1100px; } } + +a { + color: inherit; + transition: none; +} + +code, +kbd { + padding: 0; + margin: 0; + background: inherit; + font-size: inherit; + font-family: monospace; +} diff --git a/packages/editor/src/hooks/default-autocompleters.js b/packages/editor/src/hooks/default-autocompleters.js index bab2a07abee0b7..7bbf5382b09ca8 100644 --- a/packages/editor/src/hooks/default-autocompleters.js +++ b/packages/editor/src/hooks/default-autocompleters.js @@ -7,22 +7,16 @@ import { clone } from 'lodash'; * WordPress dependencies */ import { addFilter } from '@wordpress/hooks'; -import { getDefaultBlockName } from '@wordpress/blocks'; /** * Internal dependencies */ -import { blockAutocompleter, userAutocompleter } from '../components'; +import { userAutocompleter } from '../components'; -function setDefaultCompleters( completers = [], blockName ) { +function setDefaultCompleters( completers = [] ) { // Provide copies so filters may directly modify them. completers.push( clone( userAutocompleter ) ); - // Add blocks autocompleter for Paragraph block - if ( blockName === getDefaultBlockName() ) { - completers.push( clone( blockAutocompleter ) ); - } - return completers; } diff --git a/packages/editor/src/style.scss b/packages/editor/src/style.scss index 83a75edd9013ac..88ed59125a939b 100644 --- a/packages/editor/src/style.scss +++ b/packages/editor/src/style.scss @@ -9,7 +9,6 @@ @import "./components/post-format/style.scss"; @import "./components/post-last-revision/style.scss"; @import "./components/post-locked-modal/style.scss"; -@import "./components/post-permalink/style.scss"; @import "./components/post-publish-button/style.scss"; @import "./components/post-publish-panel/style.scss"; @import "./components/post-saved-state/style.scss"; diff --git a/packages/editor/src/utils/test/url.js b/packages/editor/src/utils/test/url.js index 50be061f75028f..ffe0568bbc502f 100644 --- a/packages/editor/src/utils/test/url.js +++ b/packages/editor/src/utils/test/url.js @@ -5,7 +5,7 @@ import { cleanForSlug } from '../url'; describe( 'cleanForSlug()', () => { it( 'Should return string prepared for use as url slug', () => { - expect( cleanForSlug( ' /DΓ©jΓ _vu. ' ) ).toBe( 'deja-vu' ); + expect( cleanForSlug( '/Is th@t DΓ©jΓ _vu? ' ) ).toBe( 'is-tht-deja_vu' ); } ); it( 'Should return an empty string for missing argument', () => { diff --git a/packages/editor/src/utils/url.js b/packages/editor/src/utils/url.js index 8508329a8776e5..bf2130be9caa7f 100644 --- a/packages/editor/src/utils/url.js +++ b/packages/editor/src/utils/url.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { deburr, toLower, trim } from 'lodash'; +import { deburr, trim } from 'lodash'; /** * WordPress dependencies @@ -28,11 +28,11 @@ export function getWPAdminURL( page, query ) { * This replicates some of what sanitize_title() does in WordPress core, but * is only designed to approximate what the slug will be. * - * Converts whitespace, periods, forward slashes and underscores to hyphens. * Converts Latin-1 Supplement and Latin Extended-A letters to basic Latin - * letters. Removes combining diacritical marks. Converts remaining string - * to lowercase. It does not touch octets, HTML entities, or other encoded - * characters. + * letters. Removes combining diacritical marks. Converts whitespace, periods, + * and forward slashes to hyphens. Removes any remaining non-word characters + * except hyphens. Converts remaining string to lowercase. It does not account + * for octets, HTML entities, or other encoded characters. * * @param {string} string Title or slug to be processed * @@ -42,7 +42,11 @@ export function cleanForSlug( string ) { if ( ! string ) { return ''; } - return toLower( - deburr( trim( string.replace( /[\s\./_]+/g, '-' ), '-' ) ) + return trim( + deburr( string ) + .replace( /[\s\./]+/g, '-' ) + .replace( /[^\w-]+/g, '' ) + .toLowerCase(), + '-' ); } diff --git a/packages/element/CHANGELOG.md b/packages/element/CHANGELOG.md index 6fa9e71bbb9593..6dc12e38828b8e 100644 --- a/packages/element/CHANGELOG.md +++ b/packages/element/CHANGELOG.md @@ -1,5 +1,17 @@ ## Master +## 2.13.1 (2020-04-15) + +### Bug Fix + +- Hide TypeScript type declarations ([#21613](https://github.com/WordPress/gutenberg/pull/21613)) + after they were found to conflict with DefinitelyTyped provided declarations. + +## 2.13.0 (2020-04-15) + +### New Features + +- Include TypeScript type declarations ([#21248](https://github.com/WordPress/gutenberg/pull/21248)) - Graduated `__experimentalCreateInterpolateElement` function to stable api: `createInterpolateElement` (see [20699](https://github.com/WordPress/gutenberg/pull/20699)) ## 2.10.0 (2019-12-19) diff --git a/packages/element/README.md b/packages/element/README.md index 1a51dea4046de9..c1f819f6116f5f 100755 --- a/packages/element/README.md +++ b/packages/element/README.md @@ -180,7 +180,7 @@ _Related_ _Parameters_ -- _child_ `WPElement`: Any renderable child, such as an element, string, or fragment. +- _child_ (unknown type): Any renderable child, such as an element, string, or fragment. - _container_ `HTMLElement`: DOM node into which element should be rendered. <a name="createRef" href="#createRef">#</a> **createRef** @@ -199,7 +199,7 @@ Finds the dom node of a React component. _Parameters_ -- _component_ `WPComponent`: Component's instance. +- _component_ (unknown type): Component's instance. <a name="forwardRef" href="#forwardRef">#</a> **forwardRef** @@ -289,13 +289,11 @@ aside from `children` are passed. _Parameters_ -- _props_ `Object`: -- _props.children_ `string`: HTML to render. -- _props.props_ `Object`: Any additonal props to be set on the containing div. +- _props_ `RawHTMLProps`: Children should be a string of HTML. Other props will be passed through to div wrapper. _Returns_ -- `WPComponent`: Dangerously-rendering component. +- `JSX.Element`: Dangerously-rendering component. <a name="render" href="#render">#</a> **render** @@ -303,7 +301,7 @@ Renders a given element into the target DOM node. _Parameters_ -- _element_ `WPElement`: Element to render. +- _element_ (unknown type): Element to render. - _target_ `HTMLElement`: DOM node into which element should be rendered. <a name="renderToString" href="#renderToString">#</a> **renderToString** @@ -312,9 +310,9 @@ Serializes a React element to string. _Parameters_ -- _element_ `WPElement`: Element to serialize. -- _context_ `?Object`: Context object. -- _legacyContext_ `?Object`: Legacy context object. +- _element_ (unknown type): Element to serialize. +- _context_ `[Object]`: Context object. +- _legacyContext_ `[Object]`: Legacy context object. _Returns_ diff --git a/packages/element/package.json b/packages/element/package.json index 24a1efe4ef6091..4542ddcbfd9565 100644 --- a/packages/element/package.json +++ b/packages/element/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/element", - "version": "2.11.0", + "version": "2.13.1", "description": "Element React module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -23,7 +23,7 @@ "react-native": "src/index", "sideEffects": false, "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/escape-html": "file:../escape-html", "lodash": "^4.17.15", "react": "^16.9.0", diff --git a/packages/element/src/create-interpolate-element.js b/packages/element/src/create-interpolate-element.js index e6d0eefdd3bfa3..d3da32354bb119 100644 --- a/packages/element/src/create-interpolate-element.js +++ b/packages/element/src/create-interpolate-element.js @@ -3,6 +3,8 @@ */ import { createElement, cloneElement, Fragment, isValidElement } from 'react'; +/** @typedef {import('./react').WPElement} WPElement */ + let indoc, offset, output, stack; /** @@ -22,6 +24,24 @@ let indoc, offset, output, stack; */ const tokenizer = /<(\/)?(\w+)\s*(\/)?>/g; +/** + * The stack frame tracking parse progress. + * + * @typedef Frame + * + * @property {WPElement} element A parent element which may still have + * @property {number} tokenStart Offset at which parent element first + * appears. + * @property {number} tokenLength Length of string marking start of parent + * element. + * @property {number} [prevOffset] Running offset at which parsing should + * continue. + * @property {number} [leadingTextStart] Offset at which last closing element + * finished, used for finding text between + * elements. + * @property {WPElement[]} children Children. + */ + /** * Tracks recursive-descent parse state. * @@ -29,21 +49,21 @@ const tokenizer = /<(\/)?(\w+)\s*(\/)?>/g; * parsed. * * @private - * @param {WPElement} element A parent element which may still have - * nested children not yet parsed. - * @param {number} tokenStart Offset at which parent element first - * appears. - * @param {number} tokenLength Length of string marking start of parent - * element. - * @param {number} prevOffset Running offset at which parsing should - * continue. - * @param {number} leadingTextStart Offset at which last closing element - * finished, used for finding text between - * elements + * @param {WPElement} element A parent element which may still have + * nested children not yet parsed. + * @param {number} tokenStart Offset at which parent element first + * appears. + * @param {number} tokenLength Length of string marking start of parent + * element. + * @param {number} [prevOffset] Running offset at which parsing should + * continue. + * @param {number} [leadingTextStart] Offset at which last closing element + * finished, used for finding text between + * elements. * * @return {Frame} The stack frame tracking parse progress. */ -function Frame( +function createFrame( element, tokenStart, tokenLength, @@ -175,14 +195,14 @@ function proceed( conversionMap ) { // otherwise we found an inner element addChild( - new Frame( conversionMap[ name ], startOffset, tokenLength ) + createFrame( conversionMap[ name ], startOffset, tokenLength ) ); offset = startOffset + tokenLength; return true; case 'opener': stack.push( - new Frame( + createFrame( conversionMap[ name ], startOffset, tokenLength, @@ -210,7 +230,7 @@ function proceed( conversionMap ) { ); stackTop.children.push( text ); stackTop.prevOffset = startOffset + tokenLength; - const frame = new Frame( + const frame = createFrame( stackTop.element, stackTop.tokenStart, stackTop.tokenLength, diff --git a/packages/element/src/raw-html.js b/packages/element/src/raw-html.js index 0f56060e3057b6..f75a9ff66e4fca 100644 --- a/packages/element/src/raw-html.js +++ b/packages/element/src/raw-html.js @@ -3,17 +3,21 @@ */ import { createElement } from './react'; +// Disable reason: JSDoc linter doesn't seem to parse the union (`&`) correctly. +/* eslint-disable jsdoc/valid-types */ +/** @typedef {{children: string} & import('react').ComponentPropsWithoutRef<'div'>} RawHTMLProps */ +/* eslint-enable jsdoc/valid-types */ + /** * Component used as equivalent of Fragment with unescaped HTML, in cases where * it is desirable to render dangerous HTML without needing a wrapper element. * To preserve additional props, a `div` wrapper _will_ be created if any props * aside from `children` are passed. * - * @param {Object} props - * @param {string} props.children HTML to render. - * @param {Object} props.props Any additonal props to be set on the containing div. + * @param {RawHTMLProps} props Children should be a string of HTML. Other props + * will be passed through to div wrapper. * - * @return {WPComponent} Dangerously-rendering component. + * @return {JSX.Element} Dangerously-rendering component. */ export default function RawHTML( { children, ...props } ) { // The DIV wrapper will be stripped by serializer, unless there are diff --git a/packages/element/src/react-platform.js b/packages/element/src/react-platform.js index 44a3422ed79773..fe3d3e94a99941 100644 --- a/packages/element/src/react-platform.js +++ b/packages/element/src/react-platform.js @@ -13,7 +13,7 @@ import { * * @see https://github.com/facebook/react/issues/10309#issuecomment-318433235 * - * @param {WPElement} child Any renderable child, such as an element, + * @param {import('./react').WPElement} child Any renderable child, such as an element, * string, or fragment. * @param {HTMLElement} container DOM node into which element should be rendered. */ @@ -22,14 +22,14 @@ export { createPortal }; /** * Finds the dom node of a React component. * - * @param {WPComponent} component Component's instance. + * @param {import('./react').WPComponent} component Component's instance. */ export { findDOMNode }; /** * Renders a given element into the target DOM node. * - * @param {WPElement} element Element to render. + * @param {import('./react').WPElement} element Element to render. * @param {HTMLElement} target DOM node into which element should be rendered. */ export { render }; diff --git a/packages/element/src/react.js b/packages/element/src/react.js index 449b799ef74f89..78752a1b5a179a 100644 --- a/packages/element/src/react.js +++ b/packages/element/src/react.js @@ -37,7 +37,7 @@ import { isString } from 'lodash'; /** * Object containing a React component. * - * @typedef {import('react').Component} WPComponent + * @typedef {import('react').ComponentType} WPComponent */ /** diff --git a/packages/element/src/serialize.js b/packages/element/src/serialize.js index d5ef4e02a7758e..172657812533e4 100644 --- a/packages/element/src/serialize.js +++ b/packages/element/src/serialize.js @@ -52,7 +52,9 @@ import { import { createContext, Fragment, StrictMode, forwardRef } from './react'; import RawHTML from './raw-html'; -const { Provider, Consumer } = createContext(); +/** @typedef {import('./react').WPElement} WPElement */ + +const { Provider, Consumer } = createContext( undefined ); const ForwardRef = forwardRef( () => { return null; } ); @@ -60,14 +62,14 @@ const ForwardRef = forwardRef( () => { /** * Valid attribute types. * - * @type {Set} + * @type {Set<string>} */ const ATTRIBUTES_TYPES = new Set( [ 'string', 'boolean', 'number' ] ); /** * Element tags which can be self-closing. * - * @type {Set} + * @type {Set<string>} */ const SELF_CLOSING_TAGS = new Set( [ 'area', @@ -101,7 +103,7 @@ const SELF_CLOSING_TAGS = new Set( [ * [ tr.firstChild.textContent.trim() ]: true * } ), {} ) ).sort(); * - * @type {Set} + * @type {Set<string>} */ const BOOLEAN_ATTRIBUTES = new Set( [ 'allowfullscreen', @@ -152,7 +154,7 @@ const BOOLEAN_ATTRIBUTES = new Set( [ * * - `alt`: https://blog.whatwg.org/omit-alt * - * @type {Set} + * @type {Set<string>} */ const ENUMERATED_ATTRIBUTES = new Set( [ 'autocapitalize', @@ -195,7 +197,7 @@ const ENUMERATED_ATTRIBUTES = new Set( [ * .map( ( [ key ] ) => key ) * .sort(); * - * @type {Set} + * @type {Set<string>} */ const CSS_PROPERTIES_SUPPORTS_UNITLESS = new Set( [ 'animation', @@ -269,7 +271,7 @@ function isInternalAttribute( attribute ) { * @param {string} attribute Attribute name. * @param {*} value Non-normalized attribute value. * - * @return {string} Normalized attribute value. + * @return {*} Normalized attribute value. */ function getNormalAttributeValue( attribute, value ) { switch ( attribute ) { @@ -346,9 +348,9 @@ function getNormalStylePropertyValue( property, value ) { /** * Serializes a React element to string. * - * @param {WPElement} element Element to serialize. - * @param {?Object} context Context object. - * @param {?Object} legacyContext Legacy context object. + * @param {import('react').ReactNode} element Element to serialize. + * @param {Object} [context] Context object. + * @param {Object} [legacyContext] Legacy context object. * * @return {string} Serialized element. */ @@ -369,7 +371,10 @@ export function renderElement( element, context, legacyContext = {} ) { return element.toString(); } - const { type, props } = element; + const { + type, + props, + } = /** @type {{type?: any, props?: any}} */ ( element ); switch ( type ) { case StrictMode: @@ -434,11 +439,11 @@ export function renderElement( element, context, legacyContext = {} ) { /** * Serializes a native component type to string. * - * @param {?string} type Native component type to serialize, or null if - * rendering as fragment of children content. - * @param {Object} props Props object. - * @param {?Object} context Context object. - * @param {?Object} legacyContext Legacy context object. + * @param {?string} type Native component type to serialize, or null if + * rendering as fragment of children content. + * @param {Object} props Props object. + * @param {Object} [context] Context object. + * @param {Object} [legacyContext] Legacy context object. * * @return {string} Serialized element. */ @@ -478,13 +483,15 @@ export function renderNativeComponent( return '<' + type + attributes + '>' + content + '</' + type + '>'; } +/** @typedef {import('./react').WPComponent} WPComponent */ + /** * Serializes a non-native component type to string. * - * @param {Function} Component Component type to serialize. - * @param {Object} props Props object. - * @param {?Object} context Context object. - * @param {?Object} legacyContext Legacy context object. + * @param {WPComponent} Component Component type to serialize. + * @param {Object} props Props object. + * @param {Object} [context] Context object. + * @param {Object} [legacyContext] Legacy context object. * * @return {string} Serialized element */ @@ -494,10 +501,22 @@ export function renderComponent( context, legacyContext = {} ) { - const instance = new Component( props, legacyContext ); + const instance = new /** @type {import('react').ComponentClass} */ ( Component )( + props, + legacyContext + ); - if ( typeof instance.getChildContext === 'function' ) { - Object.assign( legacyContext, instance.getChildContext() ); + if ( + typeof ( + // Ignore reason: Current prettier reformats parens and mangles type assertion + // prettier-ignore + /** @type {{getChildContext?: () => unknown}} */ ( instance ).getChildContext + ) === 'function' + ) { + Object.assign( + legacyContext, + /** @type {{getChildContext?: () => unknown}} */ ( instance ).getChildContext() + ); } const html = renderElement( instance.render(), context, legacyContext ); @@ -508,9 +527,9 @@ export function renderComponent( /** * Serializes an array of children to string. * - * @param {Array} children Children to serialize. - * @param {?Object} context Context object. - * @param {?Object} legacyContext Legacy context object. + * @param {import('react').ReactNodeArray} children Children to serialize. + * @param {Object} [context] Context object. + * @param {Object} [legacyContext] Legacy context object. * * @return {string} Serialized children. */ diff --git a/packages/element/tsconfig.json b/packages/element/tsconfig.json new file mode 100644 index 00000000000000..1f90b9c762ae63 --- /dev/null +++ b/packages/element/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "src", + "declarationDir": "build-types", + + "noImplicitAny": false, + "strictNullChecks": false + }, + "references": [ { "path": "../escape-html" } ], + "include": [ "src/**/*" ] +} diff --git a/packages/env/CHANGELOG.md b/packages/env/CHANGELOG.md index 774afe9e90411e..5a67af6ef1d623 100644 --- a/packages/env/CHANGELOG.md +++ b/packages/env/CHANGELOG.md @@ -1,5 +1,7 @@ ## Master +## 1.1.0 (2020-04-01) + ### New Feature - URLs for ZIP files are now supported as core, plugin, and theme sources. diff --git a/packages/env/README.md b/packages/env/README.md index 4b7eedc02c57fa..e27fba038c9aeb 100644 --- a/packages/env/README.md +++ b/packages/env/README.md @@ -201,6 +201,14 @@ ID user_login display_name user_email user_registered roles βœ” Ran `wp user list` in 'cli'. (in 2s 374ms) ``` +### `docker logs -f [container_id] >/dev/null` + +```sh +docker logs -f <container_id> >/dev/null + +Shows the error logs of the specified container in the terminal. The container_id is the one that is visible with `docker ps -a` +``` + ## .wp-env.json You can customize the WordPress installation, plugins and themes that the development environment will use by specifying a `.wp-env.json` file in the directory that you run `wp-env` from. @@ -209,7 +217,7 @@ You can customize the WordPress installation, plugins and themes that the develo | Field | Type | Default | Description | | ------------- | ------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------- | -| `"core"` | `string|null` | `null` | The WordPress installation to use. If `null` is specified, `wp-env` will use the latest production release of WordPress. | +| `"core"` | `string\|null` | `null` | The WordPress installation to use. If `null` is specified, `wp-env` will use the latest production release of WordPress. | | `"plugins"` | `string[]` | `[]` | A list of plugins to install and activate in the environment. | | `"themes"` | `string[]` | `[]` | A list of themes to install in the environment. The first theme in the list will be activated. | | `"port"` | `integer` | `8888` | The primary port number to use for the insallation. You'll access the instance through the port: 'http://localhost:8888'. | @@ -222,8 +230,8 @@ Several types of strings can be passed into the `core`, `plugins`, and `themes` | Type | Format | Example(s) | | ----------------- | ----------------------------- | -------------------------------------------------------- | -| Relative path | `.<path>|~<path>` | `"./a/directory"`, `"../a/directory"`, `"~/a/directory"` | -| Absolute path | `/<path>|<letter>:\<path>` | `"/a/directory"`, `"C:\\a\\directory"` | +| Relative path | `.<path>\|~<path>` | `"./a/directory"`, `"../a/directory"`, `"~/a/directory"` | +| Absolute path | `/<path>\|<letter>:\<path>` | `"/a/directory"`, `"C:\\a\\directory"` | | GitHub repository | `<owner>/<repo>[#<ref>]` | `"WordPress/WordPress"`, `"WordPress/gutenberg#master"` | | ZIP File | `http[s]://<host>/<path>.zip` | `"https://wordpress.org/wordpress-5.4-beta2.zip"` | diff --git a/packages/env/lib/build-docker-compose-config.js b/packages/env/lib/build-docker-compose-config.js index 8bc85da9f13262..e5ab685f4b1478 100644 --- a/packages/env/lib/build-docker-compose-config.js +++ b/packages/env/lib/build-docker-compose-config.js @@ -43,13 +43,56 @@ module.exports = function buildDockerComposeConfig( config ) { ...themeMounts, ]; - const testsMounts = [ - `${ - config.coreSource ? config.coreSource.testsPath : 'tests-wordpress' - }:/var/www/html`, - ...pluginMounts, - ...themeMounts, - ]; + let testsMounts; + if ( config.coreSource ) { + testsMounts = [ + `${ config.coreSource.testsPath }:/var/www/html`, + + // When using a local source for "core" we want to ensure two things: + // + // 1. That changes the user makes within the "core" directory are + // served in both the development and tests environments. + // 2. That the development and tests environment use separate + // databases and `wp-content/uploads`. + // + // To do this we copy the local "core" files ($wordpress) to a tests + // directory ($tests-wordpress) and instruct the tests environment + // to source its files like so: + // + // - wp-config.php <- $tests-wordpress/wp-config.php + // - wp-config-sample.php <- $tests-wordpress/wp-config.php + // - wp-content <- $tests-wordpress/wp-content + // - * <- $wordpress/* + // + // https://github.com/WordPress/gutenberg/issues/21164 + ...( config.coreSource.type === 'local' + ? fs + .readdirSync( config.coreSource.path ) + .filter( + ( filename ) => + filename !== 'wp-config.php' && + filename !== 'wp-config-sample.php' && + filename !== 'wp-content' + ) + .map( + ( filename ) => + `${ path.join( + config.coreSource.path, + filename + ) }:/var/www/html/${ filename }` + ) + : [] ), + + ...pluginMounts, + ...themeMounts, + ]; + } else { + testsMounts = [ + 'tests-wordpress:/var/www/html', + ...pluginMounts, + ...themeMounts, + ]; + } // Set the default ports based on the config values. const developmentPorts = `\${WP_ENV_PORT:-${ config.port }}:80`; @@ -66,6 +109,7 @@ module.exports = function buildDockerComposeConfig( config ) { services: { mysql: { image: 'mariadb', + ports: [ '3306' ], environment: { MYSQL_ALLOW_EMPTY_PASSWORD: 'yes', }, diff --git a/packages/env/lib/commands/clean.js b/packages/env/lib/commands/clean.js new file mode 100644 index 00000000000000..1a24adca8cadbc --- /dev/null +++ b/packages/env/lib/commands/clean.js @@ -0,0 +1,44 @@ +/** + * Internal dependencies + */ +const initConfig = require( '../init-config' ); +const { configureWordPress, resetDatabase } = require( '../wordpress' ); + +/** + * Wipes the development server's database, the tests server's database, or both. + * + * @param {Object} options + * @param {string} options.environment The environment to clean. Either 'development', 'tests', or 'all'. + * @param {Object} options.spinner A CLI spinner which indicates progress. + * @param {boolean} options.debug True if debug mode is enabled. + */ +module.exports = async function clean( { environment, spinner, debug } ) { + const config = await initConfig( { spinner, debug } ); + + const description = `${ environment } environment${ + environment === 'all' ? 's' : '' + }`; + spinner.text = `Cleaning ${ description }.`; + + const tasks = []; + + if ( environment === 'all' || environment === 'development' ) { + tasks.push( + resetDatabase( 'development', config ) + .then( () => configureWordPress( 'development', config ) ) + .catch( () => {} ) + ); + } + + if ( environment === 'all' || environment === 'tests' ) { + tasks.push( + resetDatabase( 'tests', config ) + .then( () => configureWordPress( 'tests', config ) ) + .catch( () => {} ) + ); + } + + await Promise.all( tasks ); + + spinner.text = `Cleaned ${ description }.`; +}; diff --git a/packages/env/lib/commands/index.js b/packages/env/lib/commands/index.js new file mode 100644 index 00000000000000..d301eab7ae3c2a --- /dev/null +++ b/packages/env/lib/commands/index.js @@ -0,0 +1,14 @@ +/** + * Internal dependencies + */ +const start = require( './start' ); +const stop = require( './stop' ); +const clean = require( './clean' ); +const run = require( './run' ); + +module.exports = { + start, + stop, + clean, + run, +}; diff --git a/packages/env/lib/commands/run.js b/packages/env/lib/commands/run.js new file mode 100644 index 00000000000000..02aad1407a9e5e --- /dev/null +++ b/packages/env/lib/commands/run.js @@ -0,0 +1,47 @@ +/** + * External dependencies + */ +const dockerCompose = require( 'docker-compose' ); + +/** + * Internal dependencies + */ +const initConfig = require( '../init-config' ); + +/** + * Runs an arbitrary command on the given Docker container. + * + * @param {Object} options + * @param {Object} options.container The Docker container to run the command on. + * @param {Object} options.command The command to run. + * @param {Object} options.spinner A CLI spinner which indicates progress. + * @param {boolean} options.debug True if debug mode is enabled. + */ +module.exports = async function run( { container, command, spinner, debug } ) { + const config = await initConfig( { spinner, debug } ); + + command = command.join( ' ' ); + + spinner.text = `Running \`${ command }\` in '${ container }'.`; + + const result = await dockerCompose.run( container, command, { + config: config.dockerComposeConfigPath, + commandOptions: [ '--rm' ], + log: config.debug, + } ); + + if ( result.out ) { + // eslint-disable-next-line no-console + console.log( + process.stdout.isTTY ? `\n\n${ result.out }\n\n` : result.out + ); + } else if ( result.err ) { + // eslint-disable-next-line no-console + console.error( + process.stdout.isTTY ? `\n\n${ result.err }\n\n` : result.err + ); + throw result.err; + } + + spinner.text = `Ran \`${ command }\` in '${ container }'.`; +}; diff --git a/packages/env/lib/commands/start.js b/packages/env/lib/commands/start.js new file mode 100644 index 00000000000000..16aa48d40302e7 --- /dev/null +++ b/packages/env/lib/commands/start.js @@ -0,0 +1,191 @@ +/** + * External dependencies + */ +const dockerCompose = require( 'docker-compose' ); +const util = require( 'util' ); +const path = require( 'path' ); +const fs = require( 'fs' ).promises; +const inquirer = require( 'inquirer' ); + +/** + * Promisified dependencies + */ +const sleep = util.promisify( setTimeout ); +const rimraf = util.promisify( require( 'rimraf' ) ); + +/** + * Internal dependencies + */ +const retry = require( '../retry' ); +const stop = require( './stop' ); +const initConfig = require( '../init-config' ); +const downloadSource = require( '../download-source' ); +const { + checkDatabaseConnection, + makeContentDirectoriesWritable, + configureWordPress, + copyCoreFiles, +} = require( '../wordpress' ); + +/** + * Starts the development server. + * + * @param {Object} options + * @param {Object} options.spinner A CLI spinner which indicates progress. + * @param {boolean} options.debug True if debug mode is enabled. + */ +module.exports = async function start( { spinner, debug } ) { + /** + * If the Docker image is already running and the `wp-env` files have been + * deleted, the start command will not complete successfully. Stopping + * the container before continuing allows the docker entrypoint script, + * which restores the files, to run again when we start the containers. + * + * Additionally, this serves as a way to restart the container entirely + * should the need arise. + * + * @see https://github.com/WordPress/gutenberg/pull/20253#issuecomment-587228440 + */ + await stop( { spinner, debug } ); + + await checkForLegacyInstall( spinner ); + + const config = await initConfig( { spinner, debug } ); + + spinner.text = 'Downloading WordPress.'; + + const progresses = {}; + const getProgressSetter = ( id ) => ( progress ) => { + progresses[ id ] = progress; + spinner.text = + 'Downloading WordPress.\n' + + Object.entries( progresses ) + .map( + ( [ key, value ] ) => + ` - ${ key }: ${ ( value * 100 ).toFixed( 0 ) }/100%` + ) + .join( '\n' ); + }; + + await Promise.all( [ + // Preemptively start the database while we wait for sources to download. + dockerCompose.upOne( 'mysql', { + config: config.dockerComposeConfigPath, + log: config.debug, + } ), + + ( async () => { + if ( config.coreSource ) { + await downloadSource( config.coreSource, { + onProgress: getProgressSetter( 'core' ), + spinner, + debug: config.debug, + } ); + await copyCoreFiles( + config.coreSource.path, + config.coreSource.testsPath + ); + } + } )(), + + ...config.pluginSources.map( ( source ) => + downloadSource( source, { + onProgress: getProgressSetter( source.basename ), + spinner, + debug: config.debug, + } ) + ), + + ...config.themeSources.map( ( source ) => + downloadSource( source, { + onProgress: getProgressSetter( source.basename ), + spinner, + debug: config.debug, + } ) + ), + ] ); + + spinner.text = 'Starting WordPress.'; + + await dockerCompose.upMany( [ 'wordpress', 'tests-wordpress' ], { + config: config.dockerComposeConfigPath, + log: config.debug, + } ); + + if ( config.coreSource === null ) { + // Don't chown wp-content when it exists on the user's local filesystem. + await Promise.all( [ + makeContentDirectoriesWritable( 'development', config ), + makeContentDirectoriesWritable( 'tests', config ), + ] ); + } + + try { + await checkDatabaseConnection( config ); + } catch ( error ) { + // Wait 30 seconds for MySQL to accept connections. + await retry( () => checkDatabaseConnection( config ), { + times: 30, + delay: 1000, + } ); + + // It takes 3-4 seconds for MySQL to be ready after it starts accepting connections. + await sleep( 4000 ); + } + + // Retry WordPress installation in case MySQL *still* wasn't ready. + await Promise.all( [ + retry( () => configureWordPress( 'development', config ), { + times: 2, + } ), + retry( () => configureWordPress( 'tests', config ), { times: 2 } ), + ] ); + + spinner.text = 'WordPress started.'; +}; + +/** + * Checks for legacy installs and provides + * the user the option to delete them. + * + * @param {Object} spinner A CLI spinner which indicates progress. + */ +async function checkForLegacyInstall( spinner ) { + const basename = path.basename( process.cwd() ); + const installs = [ + `../${ basename }-wordpress`, + `../${ basename }-tests-wordpress`, + ]; + await Promise.all( + installs.map( ( install ) => + fs + .access( install ) + .catch( () => + installs.splice( installs.indexOf( install ), 1 ) + ) + ) + ); + if ( ! installs.length ) { + return; + } + + spinner.info( + `It appears that you have used a previous version of this tool where installs were kept in ${ installs.join( + ' and ' + ) }. Installs are now in your home folder.\n` + ); + const { yesDelete } = await inquirer.prompt( [ + { + type: 'confirm', + name: 'yesDelete', + message: + 'Do you wish to delete these old installs to reclaim disk space?', + default: true, + }, + ] ); + if ( yesDelete ) { + await Promise.all( installs.map( ( install ) => rimraf( install ) ) ); + spinner.info( 'Old installs deleted successfully.' ); + } + spinner.start(); +} diff --git a/packages/env/lib/commands/stop.js b/packages/env/lib/commands/stop.js new file mode 100644 index 00000000000000..4f6688003ebb9d --- /dev/null +++ b/packages/env/lib/commands/stop.js @@ -0,0 +1,32 @@ +/** + * External dependencies + */ +const dockerCompose = require( 'docker-compose' ); + +/** + * Internal dependencies + */ +const initConfig = require( '../init-config' ); + +/** + * Stops the development server. + * + * @param {Object} options + * @param {Object} options.spinner A CLI spinner which indicates progress. + * @param {boolean} options.debug True if debug mode is enabled. + */ +module.exports = async function stop( { spinner, debug } ) { + const { dockerComposeConfigPath } = await initConfig( { + spinner, + debug, + } ); + + spinner.text = 'Stopping WordPress.'; + + await dockerCompose.down( { + config: dockerComposeConfigPath, + log: debug, + } ); + + spinner.text = 'Stopped WordPress.'; +}; diff --git a/packages/env/lib/download-source.js b/packages/env/lib/download-source.js index 74bf5f1c4fb563..0e594312f37273 100644 --- a/packages/env/lib/download-source.js +++ b/packages/env/lib/download-source.js @@ -5,14 +5,13 @@ const util = require( 'util' ); const NodeGit = require( 'nodegit' ); const fs = require( 'fs' ); -const requestProgress = require( 'request-progress' ); -const request = require( 'request' ); +const got = require( 'got' ); const path = require( 'path' ); /** * Promisified dependencies */ -const finished = util.promisify( require( 'stream' ).finished ); +const pipeline = util.promisify( require( 'stream' ).pipeline ); const extractZip = util.promisify( require( 'extract-zip' ) ); const rimraf = util.promisify( require( 'rimraf' ) ); const copyDir = util.promisify( require( 'copy-dir' ) ); @@ -132,11 +131,12 @@ async function downloadZipSource( source, { onProgress, spinner, debug } ) { log( 'Downloading zip file.' ); const zipName = `${ source.path }.zip`; const zipFile = fs.createWriteStream( zipName ); - await finished( - requestProgress( request( source.url ) ) - .on( 'progress', ( { percent } ) => onProgress( percent ) ) - .pipe( zipFile ) + + const responseStream = got.stream( source.url ); + responseStream.on( 'downloadProgress', ( { percent } ) => + onProgress( percent ) ); + await pipeline( responseStream, zipFile ); log( 'Extracting to temporary folder.' ); const dirName = `${ source.path }.temp`; diff --git a/packages/env/lib/env.js b/packages/env/lib/env.js index 02070c2b07672f..3942a307109377 100644 --- a/packages/env/lib/env.js +++ b/packages/env/lib/env.js @@ -1,528 +1,11 @@ 'use strict'; -/** - * External dependencies - */ -const util = require( 'util' ); -const path = require( 'path' ); -const fs = require( 'fs' ).promises; -const dockerCompose = require( 'docker-compose' ); -const yaml = require( 'js-yaml' ); -const inquirer = require( 'inquirer' ); - -/** - * Promisified dependencies - */ -const copyDir = util.promisify( require( 'copy-dir' ) ); -const sleep = util.promisify( setTimeout ); -const rimraf = util.promisify( require( 'rimraf' ) ); - /** * Internal dependencies */ -const { ValidationError, readConfig } = require( './config' ); -const downloadSource = require( './download-source' ); -const buildDockerComposeConfig = require( './build-docker-compose-config' ); - -/** - * @typedef {import('./config').Config} Config - */ +const { ValidationError } = require( './config' ); +const commands = require( './commands' ); module.exports = { - /** - * Starts the development server. - * - * @param {Object} options - * @param {Object} options.spinner A CLI spinner which indicates progress. - * @param {boolean} options.debug True if debug mode is enabled. - */ - async start( { spinner, debug } ) { - /** - * If the Docker image is already running and the `wp-env` files have been - * deleted, the start command will not complete successfully. Stopping - * the container before continuing allows the docker entrypoint script, - * which restores the files, to run again when we start the containers. - * - * Additionally, this serves as a way to restart the container entirely - * should the need arise. - * - * @see https://github.com/WordPress/gutenberg/pull/20253#issuecomment-587228440 - */ - await module.exports.stop( { spinner, debug } ); - - await checkForLegacyInstall( spinner ); - - const config = await initConfig( { spinner, debug } ); - - spinner.text = 'Downloading WordPress.'; - - const progresses = {}; - const getProgressSetter = ( id ) => ( progress ) => { - progresses[ id ] = progress; - spinner.text = - 'Downloading WordPress.\n' + - Object.entries( progresses ) - .map( - ( [ key, value ] ) => - ` - ${ key }: ${ ( value * 100 ).toFixed( - 0 - ) }/100%` - ) - .join( '\n' ); - }; - - await Promise.all( [ - // Preemptively start the database while we wait for sources to download. - dockerCompose.upOne( 'mysql', { - config: config.dockerComposeConfigPath, - log: config.debug, - } ), - - ( async () => { - if ( config.coreSource ) { - await downloadSource( config.coreSource, { - onProgress: getProgressSetter( 'core' ), - spinner, - debug: config.debug, - } ); - await copyCoreFiles( - config.coreSource.path, - config.coreSource.testsPath - ); - } - } )(), - - ...config.pluginSources.map( ( source ) => - downloadSource( source, { - onProgress: getProgressSetter( source.basename ), - spinner, - debug: config.debug, - } ) - ), - - ...config.themeSources.map( ( source ) => - downloadSource( source, { - onProgress: getProgressSetter( source.basename ), - spinner, - debug: config.debug, - } ) - ), - ] ); - - spinner.text = 'Starting WordPress.'; - - await dockerCompose.upMany( [ 'wordpress', 'tests-wordpress' ], { - config: config.dockerComposeConfigPath, - log: config.debug, - } ); - - if ( config.coreSource === null ) { - // Don't chown wp-content when it exists on the user's local filesystem. - await Promise.all( [ - makeContentDirectoriesWritable( 'development', config ), - makeContentDirectoriesWritable( 'tests', config ), - ] ); - } - - try { - await checkDatabaseConnection( config ); - } catch ( error ) { - // Wait 30 seconds for MySQL to accept connections. - await retry( () => checkDatabaseConnection( config ), { - times: 30, - delay: 1000, - } ); - - // It takes 3-4 seconds for MySQL to be ready after it starts accepting connections. - await sleep( 4000 ); - } - - // Retry WordPress installation in case MySQL *still* wasn't ready. - await Promise.all( [ - retry( () => configureWordPress( 'development', config ), { - times: 2, - } ), - retry( () => configureWordPress( 'tests', config ), { times: 2 } ), - ] ); - - spinner.text = 'WordPress started.'; - }, - - /** - * Stops the development server. - * - * @param {Object} options - * @param {Object} options.spinner A CLI spinner which indicates progress. - * @param {boolean} options.debug True if debug mode is enabled. - */ - async stop( { spinner, debug } ) { - const { dockerComposeConfigPath } = await initConfig( { - spinner, - debug, - } ); - - spinner.text = 'Stopping WordPress.'; - - await dockerCompose.down( { - config: dockerComposeConfigPath, - log: debug, - } ); - - spinner.text = 'Stopped WordPress.'; - }, - - /** - * Wipes the development server's database, the tests server's database, or both. - * - * @param {Object} options - * @param {string} options.environment The environment to clean. Either 'development', 'tests', or 'all'. - * @param {Object} options.spinner A CLI spinner which indicates progress. - * @param {boolean} options.debug True if debug mode is enabled. - */ - async clean( { environment, spinner, debug } ) { - const config = await initConfig( { spinner, debug } ); - - const description = `${ environment } environment${ - environment === 'all' ? 's' : '' - }`; - spinner.text = `Cleaning ${ description }.`; - - const tasks = []; - - if ( environment === 'all' || environment === 'development' ) { - tasks.push( - resetDatabase( 'development', config ) - .then( () => configureWordPress( 'development', config ) ) - .catch( () => {} ) - ); - } - - if ( environment === 'all' || environment === 'tests' ) { - tasks.push( - resetDatabase( 'tests', config ) - .then( () => configureWordPress( 'tests', config ) ) - .catch( () => {} ) - ); - } - - await Promise.all( tasks ); - - spinner.text = `Cleaned ${ description }.`; - }, - - /** - * Runs an arbitrary command on the given Docker container. - * - * @param {Object} options - * @param {Object} options.container The Docker container to run the command on. - * @param {Object} options.command The command to run. - * @param {Object} options.spinner A CLI spinner which indicates progress. - * @param {boolean} options.debug True if debug mode is enabled. - */ - async run( { container, command, spinner, debug } ) { - const config = await initConfig( { spinner, debug } ); - - command = command.join( ' ' ); - - spinner.text = `Running \`${ command }\` in '${ container }'.`; - - const result = await dockerCompose.run( container, command, { - config: config.dockerComposeConfigPath, - commandOptions: [ '--rm' ], - log: config.debug, - } ); - - if ( result.out ) { - // eslint-disable-next-line no-console - console.log( - process.stdout.isTTY ? `\n\n${ result.out }\n\n` : result.out - ); - } else if ( result.err ) { - // eslint-disable-next-line no-console - console.error( - process.stdout.isTTY ? `\n\n${ result.err }\n\n` : result.err - ); - throw result.err; - } - - spinner.text = `Ran \`${ command }\` in '${ container }'.`; - }, - + ...commands, ValidationError, }; - -/** - * Checks for legacy installs and provides - * the user the option to delete them. - * - * @param {Object} spinner A CLI spinner which indicates progress. - */ -async function checkForLegacyInstall( spinner ) { - const basename = path.basename( process.cwd() ); - const installs = [ - `../${ basename }-wordpress`, - `../${ basename }-tests-wordpress`, - ]; - await Promise.all( - installs.map( ( install ) => - fs - .access( install ) - .catch( () => - installs.splice( installs.indexOf( install ), 1 ) - ) - ) - ); - if ( ! installs.length ) { - return; - } - - spinner.info( - `It appears that you have used a previous version of this tool where installs were kept in ${ installs.join( - ' and ' - ) }. Installs are now in your home folder.\n` - ); - const { yesDelete } = await inquirer.prompt( [ - { - type: 'confirm', - name: 'yesDelete', - message: - 'Do you wish to delete these old installs to reclaim disk space?', - default: true, - }, - ] ); - if ( yesDelete ) { - await Promise.all( installs.map( ( install ) => rimraf( install ) ) ); - spinner.info( 'Old installs deleted successfully.' ); - } - spinner.start(); -} - -/** - * Initializes the local environment so that Docker commands can be run. Reads - * ./.wp-env.json, creates ~/.wp-env, and creates ~/.wp-env/docker-compose.yml. - * - * @param {Object} options - * @param {Object} options.spinner A CLI spinner which indicates progress. - * @param {boolean} options.debug True if debug mode is enabled. - * - * @return {Config} The-env config object. - */ -async function initConfig( { spinner, debug } ) { - const configPath = path.resolve( '.wp-env.json' ); - const config = await readConfig( configPath ); - config.debug = debug; - - await fs.mkdir( config.workDirectoryPath, { recursive: true } ); - - const dockerComposeConfig = buildDockerComposeConfig( config ); - await fs.writeFile( - config.dockerComposeConfigPath, - yaml.dump( dockerComposeConfig ) - ); - - if ( config.debug ) { - spinner.info( - `Config:\n${ JSON.stringify( - config, - null, - 4 - ) }\n\nDocker Compose Config:\n${ JSON.stringify( - dockerComposeConfig, - null, - 4 - ) }` - ); - spinner.start(); - } - - return config; -} - -/** - * Copies a WordPress installation, taking care to ignore large directories - * (.git, node_modules) and configuration files (wp-config.php). - * - * @param {string} fromPath Path to the WordPress directory to copy. - * @param {string} toPath Destination path. - */ -async function copyCoreFiles( fromPath, toPath ) { - await copyDir( fromPath, toPath, { - filter( stat, filepath, filename ) { - if ( stat === 'symbolicLink' ) { - return false; - } - if ( stat === 'directory' && filename === '.git' ) { - return false; - } - if ( stat === 'directory' && filename === 'node_modules' ) { - return false; - } - if ( stat === 'file' && filename === 'wp-config.php' ) { - return false; - } - return true; - }, - } ); -} - -/** - * Makes the WordPress content directories (wp-content, wp-content/plugins, - * wp-content/themes) owned by the www-data user. This ensures that WordPress - * can write to these directories. - * - * This is necessary when running wp-env with `"core": null` because Docker - * will automatically create these directories as the root user when binding - * volumes during `docker-compose up`, and `docker-compose up` doesn't support - * the `-u` option. - * - * See https://github.com/docker-library/wordpress/issues/436. - * - * @param {string} environment The environment to check. Either 'development' or 'tests'. - * @param {Config} config The wp-env config object. - */ -async function makeContentDirectoriesWritable( - environment, - { dockerComposeConfigPath, debug } -) { - await dockerCompose.exec( - environment === 'development' ? 'wordpress' : 'tests-wordpress', - 'chown www-data:www-data wp-content wp-content/plugins wp-content/themes', - { - config: dockerComposeConfigPath, - log: debug, - } - ); -} - -/** - * Performs the given action again and again until it does not throw an error. - * - * @param {Function} action The action to perform. - * @param {Object} options - * @param {number} options.times How many times to try before giving up. - * @param {number} [options.delay=5000] How long, in milliseconds, to wait between each try. - */ -async function retry( action, { times, delay = 5000 } ) { - let tries = 0; - while ( true ) { - try { - return await action(); - } catch ( error ) { - if ( ++tries >= times ) { - throw error; - } - await sleep( delay ); - } - } -} - -/** - * Checks a WordPress database connection. An error is thrown if the test is - * unsuccessful. - * - * @param {Config} config The wp-env config object. - */ -async function checkDatabaseConnection( { dockerComposeConfigPath, debug } ) { - await dockerCompose.run( 'cli', 'wp db check', { - config: dockerComposeConfigPath, - commandOptions: [ '--rm' ], - log: debug, - } ); -} - -/** - * Configures WordPress for the given environment by installing WordPress, - * activating all plugins, and activating the first theme. These steps are - * performed sequentially so as to not overload the WordPress instance. - * - * @param {string} environment The environment to configure. Either 'development' or 'tests'. - * @param {Config} config The wp-env config object. - */ -async function configureWordPress( environment, config ) { - const options = { - config: config.dockerComposeConfigPath, - commandOptions: [ '--rm' ], - log: config.debug, - }; - - const port = environment === 'development' ? config.port : config.testsPort; - - // Install WordPress. - await dockerCompose.run( - environment === 'development' ? 'cli' : 'tests-cli', - [ - 'wp', - 'core', - 'install', - `--url=localhost:${ port }`, - `--title=${ config.name }`, - '--admin_user=admin', - '--admin_password=password', - '--admin_email=wordpress@example.com', - '--skip-email', - ], - options - ); - - // Set wp-config.php values. - for ( const [ key, value ] of Object.entries( config.config ) ) { - const command = [ 'wp', 'config', 'set', key, value ]; - if ( typeof value !== 'string' ) { - command.push( '--raw' ); - } - await dockerCompose.run( - environment === 'development' ? 'cli' : 'tests-cli', - command, - options - ); - } - - // Activate all plugins. - for ( const pluginSource of config.pluginSources ) { - await dockerCompose.run( - environment === 'development' ? 'cli' : 'tests-cli', - `wp plugin activate ${ pluginSource.basename }`, - options - ); - } - - // Activate the first theme. - const [ themeSource ] = config.themeSources; - if ( themeSource ) { - await dockerCompose.run( - environment === 'development' ? 'cli' : 'tests-cli', - `wp theme activate ${ themeSource.basename }`, - options - ); - } -} - -/** - * Resets the development server's database, the tests server's database, or both. - * - * @param {string} environment The environment to clean. Either 'development', 'tests', or 'all'. - * @param {Config} config The wp-env config object. - */ -async function resetDatabase( - environment, - { dockerComposeConfigPath, debug } -) { - const options = { - config: dockerComposeConfigPath, - commandOptions: [ '--rm' ], - log: debug, - }; - - const tasks = []; - - if ( environment === 'all' || environment === 'development' ) { - tasks.push( dockerCompose.run( 'cli', 'wp db reset --yes', options ) ); - } - - if ( environment === 'all' || environment === 'tests' ) { - tasks.push( - dockerCompose.run( 'tests-cli', 'wp db reset --yes', options ) - ); - } - - await Promise.all( tasks ); -} diff --git a/packages/env/lib/init-config.js b/packages/env/lib/init-config.js new file mode 100644 index 00000000000000..6d417954428375 --- /dev/null +++ b/packages/env/lib/init-config.js @@ -0,0 +1,57 @@ +/** + * External dependencies + */ +const path = require( 'path' ); +const fs = require( 'fs' ).promises; +const yaml = require( 'js-yaml' ); + +/** + * Internal dependencies + */ +const { readConfig } = require( './config' ); +const buildDockerComposeConfig = require( './build-docker-compose-config' ); + +/** + * @typedef {import('./config').Config} Config + */ + +/** + * Initializes the local environment so that Docker commands can be run. Reads + * ./.wp-env.json, creates ~/.wp-env, and creates ~/.wp-env/docker-compose.yml. + * + * @param {Object} options + * @param {Object} options.spinner initConfigA CLI spinner which indicates progress. + * @param {boolean} options.debug True if debug mode is enabled. + * + * @return {Config} The-env config object. + */ +module.exports = async function initConfig( { spinner, debug } ) { + const configPath = path.resolve( '.wp-env.json' ); + const config = await readConfig( configPath ); + config.debug = debug; + + await fs.mkdir( config.workDirectoryPath, { recursive: true } ); + + const dockerComposeConfig = buildDockerComposeConfig( config ); + await fs.writeFile( + config.dockerComposeConfigPath, + yaml.dump( dockerComposeConfig ) + ); + + if ( config.debug ) { + spinner.info( + `Config:\n${ JSON.stringify( + config, + null, + 4 + ) }\n\nDocker Compose Config:\n${ JSON.stringify( + dockerComposeConfig, + null, + 4 + ) }` + ); + spinner.start(); + } + + return config; +}; diff --git a/packages/env/lib/retry.js b/packages/env/lib/retry.js new file mode 100644 index 00000000000000..b23705ee2cc06d --- /dev/null +++ b/packages/env/lib/retry.js @@ -0,0 +1,31 @@ +/** + * External dependencies + */ +const util = require( 'util' ); + +/** + * Promisified dependencies + */ +const sleep = util.promisify( setTimeout ); + +/** + * Performs the given action again and again until it does not throw an error. + * + * @param {Function} action The action to perform. + * @param {Object} options + * @param {number} options.times How many times to try before giving up. + * @param {number} [options.delay=5000] How long, in milliseconds, to wait between each try. + */ +module.exports = async function retry( action, { times, delay = 5000 } ) { + let tries = 0; + while ( true ) { + try { + return await action(); + } catch ( error ) { + if ( ++tries >= times ) { + throw error; + } + await sleep( delay ); + } + } +}; diff --git a/packages/env/lib/wordpress.js b/packages/env/lib/wordpress.js new file mode 100644 index 00000000000000..48910b49d38cf1 --- /dev/null +++ b/packages/env/lib/wordpress.js @@ -0,0 +1,190 @@ +/** + * External dependencies + */ +const dockerCompose = require( 'docker-compose' ); +const util = require( 'util' ); + +/** + * Promisified dependencies + */ +const copyDir = util.promisify( require( 'copy-dir' ) ); + +/** + * @typedef {import('./config').Config} Config + */ + +/** + * Makes the WordPress content directories (wp-content, wp-content/plugins, + * wp-content/themes) owned by the www-data user. This ensures that WordPress + * can write to these directories. + * + * This is necessary when running wp-env with `"core": null` because Docker + * will automatically create these directories as the root user when binding + * volumes during `docker-compose up`, and `docker-compose up` doesn't support + * the `-u` option. + * + * See https://github.com/docker-library/wordpress/issues/436. + * + * @param {string} environment The environment to check. Either 'development' or 'tests'. + * @param {Config} config The wp-env config object. + */ +async function makeContentDirectoriesWritable( + environment, + { dockerComposeConfigPath, debug } +) { + await dockerCompose.exec( + environment === 'development' ? 'wordpress' : 'tests-wordpress', + 'chown www-data:www-data wp-content wp-content/plugins wp-content/themes', + { + config: dockerComposeConfigPath, + log: debug, + } + ); +} + +/** + * Checks a WordPress database connection. An error is thrown if the test is + * unsuccessful. + * + * @param {Config} config The wp-env config object. + */ +async function checkDatabaseConnection( { dockerComposeConfigPath, debug } ) { + await dockerCompose.run( 'cli', 'wp db check', { + config: dockerComposeConfigPath, + commandOptions: [ '--rm' ], + log: debug, + } ); +} + +/** + * Configures WordPress for the given environment by installing WordPress, + * activating all plugins, and activating the first theme. These steps are + * performed sequentially so as to not overload the WordPress instance. + * + * @param {string} environment The environment to configure. Either 'development' or 'tests'. + * @param {Config} config The wp-env config object. + */ +async function configureWordPress( environment, config ) { + const options = { + config: config.dockerComposeConfigPath, + commandOptions: [ '--rm' ], + log: config.debug, + }; + + const port = environment === 'development' ? config.port : config.testsPort; + + // Install WordPress. + await dockerCompose.run( + environment === 'development' ? 'cli' : 'tests-cli', + [ + 'wp', + 'core', + 'install', + `--url=localhost:${ port }`, + `--title=${ config.name }`, + '--admin_user=admin', + '--admin_password=password', + '--admin_email=wordpress@example.com', + '--skip-email', + ], + options + ); + + // Set wp-config.php values. + for ( const [ key, value ] of Object.entries( config.config ) ) { + const command = [ 'wp', 'config', 'set', key, value ]; + if ( typeof value !== 'string' ) { + command.push( '--raw' ); + } + await dockerCompose.run( + environment === 'development' ? 'cli' : 'tests-cli', + command, + options + ); + } + + // Activate all plugins. + for ( const pluginSource of config.pluginSources ) { + await dockerCompose.run( + environment === 'development' ? 'cli' : 'tests-cli', + `wp plugin activate ${ pluginSource.basename }`, + options + ); + } + + // Activate the first theme. + const [ themeSource ] = config.themeSources; + if ( themeSource ) { + await dockerCompose.run( + environment === 'development' ? 'cli' : 'tests-cli', + `wp theme activate ${ themeSource.basename }`, + options + ); + } +} + +/** + * Resets the development server's database, the tests server's database, or both. + * + * @param {string} environment The environment to clean. Either 'development', 'tests', or 'all'. + * @param {Config} config The wp-env config object. + */ +async function resetDatabase( + environment, + { dockerComposeConfigPath, debug } +) { + const options = { + config: dockerComposeConfigPath, + commandOptions: [ '--rm' ], + log: debug, + }; + + const tasks = []; + + if ( environment === 'all' || environment === 'development' ) { + tasks.push( dockerCompose.run( 'cli', 'wp db reset --yes', options ) ); + } + + if ( environment === 'all' || environment === 'tests' ) { + tasks.push( + dockerCompose.run( 'tests-cli', 'wp db reset --yes', options ) + ); + } + + await Promise.all( tasks ); +} + +/** + * Copies a WordPress installation, taking care to ignore large directories + * (.git, node_modules) and configuration files (wp-config.php). + * + * @param {string} fromPath Path to the WordPress directory to copy. + * @param {string} toPath Destination path. + */ +async function copyCoreFiles( fromPath, toPath ) { + await copyDir( fromPath, toPath, { + filter( stat, filepath, filename ) { + if ( stat === 'symbolicLink' ) { + return false; + } + if ( stat === 'directory' && filename === '.git' ) { + return false; + } + if ( stat === 'directory' && filename === 'node_modules' ) { + return false; + } + if ( stat === 'file' && filename === 'wp-config.php' ) { + return false; + } + return true; + }, + } ); +} + +module.exports = { + makeContentDirectoriesWritable, + checkDatabaseConnection, + configureWordPress, + resetDatabase, + copyCoreFiles, +}; diff --git a/packages/env/package.json b/packages/env/package.json index 6b4069d8f4f9b4..8b66f50a865e6d 100644 --- a/packages/env/package.json +++ b/packages/env/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/env", - "version": "1.0.1", + "version": "1.2.0", "description": "A zero-config, self contained local WordPress environment for development and testing.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -32,16 +32,15 @@ "wp-env": "bin/wp-env" }, "dependencies": { - "chalk": "^2.4.2", + "chalk": "^4.0.0", "copy-dir": "^1.2.0", "docker-compose": "^0.22.2", "extract-zip": "^1.6.7", - "inquirer": "^7.0.4", + "got": "^10.7.0", + "inquirer": "^7.1.0", "js-yaml": "^3.13.1", "nodegit": "^0.26.2", "ora": "^4.0.2", - "request": "^2.88.2", - "request-progress": "^3.0.0", "rimraf": "^3.0.2", "terminal-link": "^2.0.0", "yargs": "^14.0.0" diff --git a/packages/env/test/config.js b/packages/env/test/config.js index 181a5a3baec23e..34384e95b43d91 100644 --- a/packages/env/test/config.js +++ b/packages/env/test/config.js @@ -1,4 +1,4 @@ -'use strict'; +/* eslint-disable jest/no-try-expect */ /** * External dependencies */ @@ -221,11 +221,11 @@ describe( 'readConfig', () => { it( 'should throw a validaton error if the ports are not numbers', async () => { expect.assertions( 10 ); - testPortNumberValidation( 'port', 'string' ); - testPortNumberValidation( 'testsPort', [] ); - testPortNumberValidation( 'port', {} ); - testPortNumberValidation( 'testsPort', false ); - testPortNumberValidation( 'port', null ); + await testPortNumberValidation( 'port', 'string' ); + await testPortNumberValidation( 'testsPort', [] ); + await testPortNumberValidation( 'port', {} ); + await testPortNumberValidation( 'testsPort', false ); + await testPortNumberValidation( 'port', null ); } ); it( 'should throw a validaton error if the ports are the same', async () => { @@ -415,3 +415,4 @@ async function testPortNumberValidation( portName, value ) { } jest.clearAllMocks(); } +/* eslint-enable jest/no-try-expect */ diff --git a/packages/escape-html/CHANGELOG.md b/packages/escape-html/CHANGELOG.md index 9f38d3c2bb14ef..9b236d7f334bde 100644 --- a/packages/escape-html/CHANGELOG.md +++ b/packages/escape-html/CHANGELOG.md @@ -1,3 +1,11 @@ +## Master + +## 1.8.0 (2020-04-15) + +### New feature + +- Include TypeScript type declarations ([#20669](https://github.com/WordPress/gutenberg/pull/20669)) + ## 1.2.0 (2019-03-20) - Add fix for WordPress wptexturize greater-than tokenize bug (see https://core.trac.wordpress.org/ticket/45387) diff --git a/packages/escape-html/package.json b/packages/escape-html/package.json index fab30cccc0bece..8bff939be9ad25 100644 --- a/packages/escape-html/package.json +++ b/packages/escape-html/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/escape-html", - "version": "1.7.0", + "version": "1.8.0", "description": "Escape HTML utils.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -19,9 +19,10 @@ "main": "build/index.js", "module": "build-module/index.js", "react-native": "src/index", + "types": "build-types", "sideEffects": false, "dependencies": { - "@babel/runtime": "^7.8.3" + "@babel/runtime": "^7.9.2" }, "publishConfig": { "access": "public" diff --git a/packages/escape-html/tsconfig.json b/packages/escape-html/tsconfig.json new file mode 100644 index 00000000000000..3c2c31f506f132 --- /dev/null +++ b/packages/escape-html/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "src", + "declarationDir": "build-types" + }, + "include": [ "src/**/*" ] +} diff --git a/packages/eslint-plugin/CHANGELOG.md b/packages/eslint-plugin/CHANGELOG.md index 48149ffc4c43fb..040e3b644b45ab 100644 --- a/packages/eslint-plugin/CHANGELOG.md +++ b/packages/eslint-plugin/CHANGELOG.md @@ -1,5 +1,44 @@ ## Master +### Bug Fixes + +- The `@wordpress/no-unused-vars-before-return` rule will now correctly identify valid usage of a variable as a JSX identifier. + +## 5.0.1 (2020-04-15) + +### Bug Fixes + +- Fixes an error caused by missing `utils` directory from published package ([#21609](https://github.com/WordPress/gutenberg/pull/21609)). +- Added the recommended `Prettier` config that enforces WordPress coding style guidelines ([#21602](https://github.com/WordPress/gutenberg/pull/21602)). + +## 5.0.0 (2020-04-15) + +### Breaking Changes + +- There is a new `i18n` ruleset that includes all i18n-related rules and is included in the `recommended` ruleset. +- The `@wordpress/valid-sprintf` rule has been moved from the `custom` ruleset to the `i18n` ruleset. +- The `@wordpress/valid-sprintf` rule now recognizes mix of ordered and non-ordered placeholders. +- The bundled `eslint-plugin-jest` dependency has been updated from requiring `^22.15.1` to requiring `^23.8.2` ([#21424](https://github.com/WordPress/gutenberg/pull/21424)). +- The bundled `eslint-plugin-jsdoc` dependency has been updated from requiring `^21.0.0` to requiring `^22.1.0` ([#21424](https://github.com/WordPress/gutenberg/pull/21424)). +- The bundled `eslint-plugin-react-hooks` dependency has been updated from requiring `^1.6.1` to requiring `^3.0.0` ([#21424](https://github.com/WordPress/gutenberg/pull/21424)). + +### New Features + +- New Rule: [`@wordpress/i18n-text-domain`](https://github.com/WordPress/gutenberg/blob/master/packages/eslint-plugin/docs/rules/i18n-text-domain.md) +- New Rule: [`@wordpress/i18n-translator-comments`](https://github.com/WordPress/gutenberg/blob/master/packages/eslint-plugin/docs/rules/i18n-translator-comments.md) +- New Rule: [`@wordpress/i18n-no-variables`](https://github.com/WordPress/gutenberg/blob/master/packages/eslint-plugin/docs/rules/i18n-no-variables.md) +- New Rule: [`@wordpress/i18n-no-placeholders-only`](https://github.com/WordPress/gutenberg/blob/master/packages/eslint-plugin/docs/rules/i18n-no-placeholders-only.md) +- New Rule: [`@wordpress/i18n-no-collapsible-whitespace`](https://github.com/WordPress/gutenberg/blob/master/packages/eslint-plugin/docs/rules/i18n-no-collapsible-whitespace.md) +- New Rule: [`@wordpress/i18n-ellipsis`](https://github.com/WordPress/gutenberg/blob/master/packages/eslint-plugin/docs/rules/i18n-ellipsis.md) +- The bundled `eslint-plugin-react` dependency has been updated from requiring `^7.14.3` to requiring `^7.19.0` ([#21424](https://github.com/WordPress/gutenberg/pull/21424)). + +### Bug Fixes + +- The `@wordpress/valid-sprintf` rule now detects usage of `sprintf` via `i18n.sprintf` (e.g. when using `import * as i18n from '@wordpress/i18n'`). +- `@wordpress/no-unused-vars-before-return` will correctly consider other unused variables after encountering an instance of an `excludePattern` option exception. + +## 4.1.0 (2020-04-01) + ### New Features - The `prefer-const` rule included in the `recommended` and `esnext` rulesets has been relaxed to allow a `let` assignment if any of a [destructuring assignment](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) are reassigned. diff --git a/packages/eslint-plugin/README.md b/packages/eslint-plugin/README.md index 31979f983b52f9..e6bf980d326a3f 100644 --- a/packages/eslint-plugin/README.md +++ b/packages/eslint-plugin/README.md @@ -36,6 +36,7 @@ Alternatively, you can opt-in to only the more granular rulesets offered by the - `jsdoc` - `jsx-a11y` - `react` +- `i18n` - `test-e2e` - `test-unit` diff --git a/packages/eslint-plugin/configs/custom.js b/packages/eslint-plugin/configs/custom.js index 8949b63f94d8dc..276d1f15a2584a 100644 --- a/packages/eslint-plugin/configs/custom.js +++ b/packages/eslint-plugin/configs/custom.js @@ -2,30 +2,8 @@ module.exports = { plugins: [ '@wordpress' ], rules: { '@wordpress/no-unused-vars-before-return': 'error', - '@wordpress/valid-sprintf': 'error', '@wordpress/no-base-control-with-label-without-id': 'error', '@wordpress/no-unguarded-get-range-at': 'error', - 'no-restricted-syntax': [ - 'error', - { - selector: - 'CallExpression[callee.name=/^(__|_n|_nx|_x)$/]:not([arguments.0.type=/^Literal|BinaryExpression$/])', - message: - 'Translate function arguments must be string literals.', - }, - { - selector: - 'CallExpression[callee.name=/^(_n|_nx|_x)$/]:not([arguments.1.type=/^Literal|BinaryExpression$/])', - message: - 'Translate function arguments must be string literals.', - }, - { - selector: - 'CallExpression[callee.name=_nx]:not([arguments.3.type=/^Literal|BinaryExpression$/])', - message: - 'Translate function arguments must be string literals.', - }, - ], }, overrides: [ { diff --git a/packages/eslint-plugin/configs/i18n.js b/packages/eslint-plugin/configs/i18n.js new file mode 100644 index 00000000000000..c3271214e3ef5c --- /dev/null +++ b/packages/eslint-plugin/configs/i18n.js @@ -0,0 +1,12 @@ +module.exports = { + plugins: [ '@wordpress' ], + rules: { + '@wordpress/valid-sprintf': 'error', + '@wordpress/i18n-translator-comments': 'error', + '@wordpress/i18n-text-domain': 'error', + '@wordpress/i18n-no-collapsible-whitespace': 'error', + '@wordpress/i18n-no-placeholders-only': 'error', + '@wordpress/i18n-no-variables': 'error', + '@wordpress/i18n-ellipsis': 'error', + }, +}; diff --git a/packages/eslint-plugin/configs/jsdoc.js b/packages/eslint-plugin/configs/jsdoc.js index ce2414a31add63..be11e0013dff15 100644 --- a/packages/eslint-plugin/configs/jsdoc.js +++ b/packages/eslint-plugin/configs/jsdoc.js @@ -17,6 +17,7 @@ const temporaryWordPressInternalTypes = [ 'WPBlockSerializationOptions', 'WPBlock', 'WPBlockPattern', + 'WPBlockType', 'WPBlockTypeIcon', 'WPBlockTypeIconRender', 'WPBlockTypeIconDescriptor', @@ -47,6 +48,7 @@ const typescriptUtilityTypes = [ 'IterableIterator', 'NonNullable', 'Omit', + 'Parameters', 'Partial', 'Pick', 'PromiseLike', @@ -58,6 +60,9 @@ const typescriptUtilityTypes = [ 'Required', 'ReturnType', 'ThisType', + 'unknown', + 'never', + 'NodeJS', ]; module.exports = { @@ -94,5 +99,26 @@ module.exports = { 'jsdoc/require-jsdoc': 'off', 'jsdoc/require-param-description': 'off', 'jsdoc/require-returns': 'off', + 'jsdoc/check-access': 'error', + 'jsdoc/check-alignment': 'error', + 'jsdoc/check-param-names': 'error', + 'jsdoc/check-property-names': 'error', + 'jsdoc/check-tag-names': 'error', + 'jsdoc/check-types': 'error', + 'jsdoc/check-values': 'off', + 'jsdoc/empty-tags': 'error', + 'jsdoc/implements-on-classes': 'error', + 'jsdoc/newline-after-description': 'error', + 'jsdoc/require-param': 'error', + 'jsdoc/require-param-name': 'error', + 'jsdoc/require-param-type': 'error', + 'jsdoc/require-property': 'error', + 'jsdoc/require-property-description': 'error', + 'jsdoc/require-property-name': 'error', + 'jsdoc/require-property-type': 'error', + 'jsdoc/require-returns-check': 'error', + 'jsdoc/require-returns-description': 'error', + 'jsdoc/require-returns-type': 'error', + 'jsdoc/valid-types': 'error', }, }; diff --git a/packages/eslint-plugin/configs/recommended-with-formatting.js b/packages/eslint-plugin/configs/recommended-with-formatting.js index 61e08359128075..d6e51149a928e9 100644 --- a/packages/eslint-plugin/configs/recommended-with-formatting.js +++ b/packages/eslint-plugin/configs/recommended-with-formatting.js @@ -5,6 +5,7 @@ module.exports = { require.resolve( './custom.js' ), require.resolve( './react.js' ), require.resolve( './esnext.js' ), + require.resolve( './i18n.js' ), ], env: { node: true, diff --git a/packages/eslint-plugin/configs/recommended.js b/packages/eslint-plugin/configs/recommended.js index 9e1659685a85ad..bb4fcb4f24feea 100644 --- a/packages/eslint-plugin/configs/recommended.js +++ b/packages/eslint-plugin/configs/recommended.js @@ -1,7 +1,15 @@ +/** + * WordPress dependencies + */ +const defaultPrettierConfig = require( '@wordpress/prettier-config' ); + module.exports = { extends: [ require.resolve( './recommended-with-formatting.js' ), 'plugin:prettier/recommended', 'prettier/react', ], + rules: { + 'prettier/prettier': [ 'error', defaultPrettierConfig ], + }, }; diff --git a/packages/eslint-plugin/docs/rules/i18n-ellipsis.md b/packages/eslint-plugin/docs/rules/i18n-ellipsis.md new file mode 100644 index 00000000000000..f08a43bc56af4a --- /dev/null +++ b/packages/eslint-plugin/docs/rules/i18n-ellipsis.md @@ -0,0 +1,18 @@ +# Disallow using three dots in translatable strings (i18n-ellipsis) + +Three dots for indicating an ellipsis should be replaced with the UTF-8 character … (Horizontal Ellipsis, U+2026) as it has a more semantic meaning. + +## Rule details + +Examples of **incorrect** code for this rule: + +```js +__( 'Continue...' ); + +``` + +Examples of **correct** code for this rule: + +```js +__( 'Continue…' ); +``` diff --git a/packages/eslint-plugin/docs/rules/i18n-no-collapsible-whitespace.md b/packages/eslint-plugin/docs/rules/i18n-no-collapsible-whitespace.md new file mode 100644 index 00000000000000..d9564698535a96 --- /dev/null +++ b/packages/eslint-plugin/docs/rules/i18n-no-collapsible-whitespace.md @@ -0,0 +1,26 @@ +# Disallow collapsible whitespace in translatable strings. (i18n-no-collapsible-whitespace) + +Using complex whitespace in translatable strings and relying on HTML to collapse it can make translation more difficult and lead to unnecessary retranslation. + +Whitespace can be appropriate in longer translatable content, for example a whole blog post. These cases are unlikely to occur in the code scanned by eslint but if they do, [disable the rule with inline comments](http://eslint.org/docs/user-guide/configuring#disabling-rules-with-inline-comments. ( e.g. `// eslint-disable-line i18n-no-collapsible-whitespace` ). + +## Rule details + +Examples of **incorrect** code for this rule: + +```js +__( "A string\non two lines" ); +__( 'A string\non two lines' ); +__( `A string +on two lines` ); +__( `A string with tabs` ); +__( "Multiple spaces. Even after a full stop. (We're going there)" ); +``` + +Examples of **correct** code for this rule: + +```js +__( `A long string ` + + `spread over ` + + `multiple lines.` ); +``` diff --git a/packages/eslint-plugin/docs/rules/i18n-no-placeholders-only.md b/packages/eslint-plugin/docs/rules/i18n-no-placeholders-only.md new file mode 100644 index 00000000000000..286690a79e70c0 --- /dev/null +++ b/packages/eslint-plugin/docs/rules/i18n-no-placeholders-only.md @@ -0,0 +1,17 @@ +# Prevent using only placeholders in translatable strings (i18n-no-placeholders-only) + +Translatable strings that consist of nothing but a placeholder cannot be translated. + +## Rule details + +Examples of **incorrect** code for this rule: + +```js +__( '%s' ); +``` + +Examples of **correct** code for this rule: + +```js +__( 'Hello %s' ); +``` diff --git a/packages/eslint-plugin/docs/rules/i18n-no-variables.md b/packages/eslint-plugin/docs/rules/i18n-no-variables.md new file mode 100644 index 00000000000000..3478f02acf755d --- /dev/null +++ b/packages/eslint-plugin/docs/rules/i18n-no-variables.md @@ -0,0 +1,24 @@ +# Enforce string literals as translation function arguments (i18n-no-variables) + +[Translation functions](https://github.com/WordPress/gutenberg/blob/master/packages/i18n/README.md#api) must be called with valid string literals as arguments. + +They cannot be variables or functions due to the way these strings are extracted through static analysis of the code. The exception to this rule is string concatenation within the argument itself. + +This limitation applies to both singular and plural strings, as well as the `context` argument if present. + +## Rule details + +Examples of **incorrect** code for this rule: + +```js +__( `Hello ${foo}` ); +__( foo ); +_x( 'Hello World', bar ); +``` + +Examples of **correct** code for this rule: + +```js +__( 'Hello World' ); +_x( 'Hello' + ' World', 'context', 'foo' ); +``` diff --git a/packages/eslint-plugin/docs/rules/i18n-text-domain.md b/packages/eslint-plugin/docs/rules/i18n-text-domain.md new file mode 100644 index 00000000000000..7a637fc43aaeb1 --- /dev/null +++ b/packages/eslint-plugin/docs/rules/i18n-text-domain.md @@ -0,0 +1,26 @@ +# Enforce passing valid text domains (i18n-text-domain) + +[Translation functions](https://github.com/WordPress/gutenberg/blob/master/packages/i18n/README.md#api) must be called with a valid string literal as the text domain. + +## Rule details + +Examples of **incorrect** code for this rule: + +```js +__( 'Hello World' ); // unless allowedTextDomain contains 'default' +__( 'Hello World', 'default' ); // with allowedTextDomain = [ 'default' ] +__( 'Hello World', foo ); +``` + +Examples of **correct** code for this rule: + +```js +__( 'Hello World' ); // with allowedTextDomain = [ 'default' ] +__( 'Hello World', 'foo-bar' ); // with allowedTextDomain = [ 'foo-bar' ] +``` + +## Options + +This rule accepts a single options argument: + +- Set `allowedTextDomain` to specify the list of allowed text domains, e.g. `[ 'foo', 'bar' ]`. The default is `[ 'default' ]`. diff --git a/packages/eslint-plugin/docs/rules/i18n-translator-comments.md b/packages/eslint-plugin/docs/rules/i18n-translator-comments.md new file mode 100644 index 00000000000000..59a9453e46ec01 --- /dev/null +++ b/packages/eslint-plugin/docs/rules/i18n-translator-comments.md @@ -0,0 +1,38 @@ +# Enforce adding translator comments (i18n-translator-comments) + +If using [translation functions](https://github.com/WordPress/gutenberg/blob/master/packages/i18n/README.md#api) with placeholders in them, +they need accompanying translator comments. + +## Rule details + +Examples of **incorrect** code for this rule: + +```js +var color = ''; +sprintf( __( 'Color: %s' ), color ); + +var address = ''; +sprintf( + __( 'Address: %s' ), + address +); + +// translators: %s: Name +var name = ''; +sprintf( __( 'Name: %s' ), name ); +``` + +Examples of **correct** code for this rule: + +```js +var color = ''; +// translators: %s: Color +sprintf( __( 'Color: %s' ), color ); + +var address = ''; +sprintf( + // translators: %s: Address. + __( 'Address: %s' ), + address, +); +``` diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index 554c824fa5b094..523b779afb360a 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/eslint-plugin", - "version": "4.0.0", + "version": "5.0.1", "description": "ESLint plugin for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -20,19 +20,20 @@ "files": [ "configs", "rules", + "utils", "index.js" ], "main": "index.js", "dependencies": { - "babel-eslint": "^10.0.3", - "eslint-config-prettier": "^6.10.0", - "eslint-plugin-jest": "^22.15.1", - "eslint-plugin-jsdoc": "^15.8.0", + "@wordpress/prettier-config": "file:../prettier-config", + "babel-eslint": "^10.1.0", + "eslint-config-prettier": "^6.10.1", + "eslint-plugin-jest": "^23.8.2", + "eslint-plugin-jsdoc": "^22.1.0", "eslint-plugin-jsx-a11y": "^6.2.3", "eslint-plugin-prettier": "^3.1.2", - "eslint-plugin-react": "^7.14.3", - "eslint-plugin-react-hooks": "^1.6.1", - "eslint-plugin-react-native": "^3.8.1", + "eslint-plugin-react": "^7.19.0", + "eslint-plugin-react-hooks": "^3.0.0", "globals": "^12.0.0", "prettier": "npm:wp-prettier@1.19.1", "requireindex": "^1.2.0" diff --git a/packages/eslint-plugin/rules/__tests__/i18n-ellipsis.js b/packages/eslint-plugin/rules/__tests__/i18n-ellipsis.js new file mode 100644 index 00000000000000..2bc487e92d42bd --- /dev/null +++ b/packages/eslint-plugin/rules/__tests__/i18n-ellipsis.js @@ -0,0 +1,65 @@ +/** + * External dependencies + */ +import { RuleTester } from 'eslint'; + +/** + * Internal dependencies + */ +import rule from '../i18n-ellipsis'; + +const ruleTester = new RuleTester( { + parserOptions: { + ecmaVersion: 6, + }, +} ); + +ruleTester.run( 'i18n-ellipsis', rule, { + valid: [ + { + code: `__( 'Hello World…' )`, + }, + { + code: `__( 'Hello' + 'World…' )`, + }, + { + code: `_x( 'Hello World…', 'context' )`, + }, + { + code: `_n( 'Singular…', 'Plural…', number)`, + }, + { + code: `i18n.__( 'Hello World…' )`, + }, + ], + invalid: [ + { + code: `__( 'Hello World...' )`, + output: `__( 'Hello World…' )`, + errors: [ { messageId: 'foundThreeDots' } ], + }, + { + code: `__( 'Hello' + 'World...' )`, + output: `__( 'Hello' + 'World…' )`, + errors: [ { messageId: 'foundThreeDots' } ], + }, + { + code: `_x( 'Hello World...', 'context' )`, + output: `_x( 'Hello World…', 'context' )`, + errors: [ { messageId: 'foundThreeDots' } ], + }, + { + code: `_n( 'Singular...', 'Plural...', number)`, + output: `_n( 'Singular…', 'Plural…', number)`, + errors: [ + { messageId: 'foundThreeDots' }, + { messageId: 'foundThreeDots' }, + ], + }, + { + code: `i18n.__( 'Hello World...' )`, + output: `i18n.__( 'Hello World…' )`, + errors: [ { messageId: 'foundThreeDots' } ], + }, + ], +} ); diff --git a/packages/eslint-plugin/rules/__tests__/i18n-no-collapsible-whitespace.js b/packages/eslint-plugin/rules/__tests__/i18n-no-collapsible-whitespace.js new file mode 100644 index 00000000000000..35e4e47301d7aa --- /dev/null +++ b/packages/eslint-plugin/rules/__tests__/i18n-no-collapsible-whitespace.js @@ -0,0 +1,62 @@ +/** + * External dependencies + */ +import { RuleTester } from 'eslint'; + +/** + * Internal dependencies + */ +import rule from '../i18n-no-collapsible-whitespace'; + +const ruleTester = new RuleTester( { + parserOptions: { + ecmaVersion: 6, + }, +} ); + +ruleTester.run( 'i18n-no-collapsible-whitespace', rule, { + valid: [ + { + code: `__( 'Hello World…' )`, + }, + { + code: + '__( `A long string ` +\n `spread over ` +\n `multiple lines.` );', + }, + ], + invalid: [ + { + code: '__( "My double-quoted string\\nwith a newline" );', + errors: [ { messageId: 'noCollapsibleWhitespace' } ], + }, + { + code: "__( 'My single quoted string\\nwith a newline' );", + errors: [ { messageId: 'noCollapsibleWhitespace' } ], + }, + { + code: '__( `My template literal\non two lines` );', + errors: [ { messageId: 'noCollapsibleWhitespace' } ], + }, + { + code: "__( ' My tab-indented string.' );", + errors: [ { messageId: 'noCollapsibleWhitespace' } ], + }, + { + code: "__( '\tMy string with a tab escape sequence.' );", + errors: [ { messageId: 'noCollapsibleWhitespace' } ], + }, + { + code: "__( '\u0009My string with a unicode tab.' );", + errors: [ { messageId: 'noCollapsibleWhitespace' } ], + }, + { + code: '__( `A string with \r a carriage return.` );', + errors: [ { messageId: 'noCollapsibleWhitespace' } ], + }, + { + code: + "__( 'A string with consecutive spaces. These two are after a full stop.' );", + errors: [ { messageId: 'noCollapsibleWhitespace' } ], + }, + ], +} ); diff --git a/packages/eslint-plugin/rules/__tests__/i18n-no-placeholders-only.js b/packages/eslint-plugin/rules/__tests__/i18n-no-placeholders-only.js new file mode 100644 index 00000000000000..7743798805267c --- /dev/null +++ b/packages/eslint-plugin/rules/__tests__/i18n-no-placeholders-only.js @@ -0,0 +1,50 @@ +/** + * External dependencies + */ +import { RuleTester } from 'eslint'; + +/** + * Internal dependencies + */ +import rule from '../i18n-no-placeholders-only'; + +const ruleTester = new RuleTester( { + parserOptions: { + ecmaVersion: 6, + }, +} ); + +ruleTester.run( 'i18n-no-placeholders-only', rule, { + valid: [ + { + code: `__( 'Hello %s' )`, + }, + { + code: `i18n.__( 'Hello %s' )`, + }, + { + code: `__( '%d%%' )`, + }, + ], + invalid: [ + { + code: `__( '%s' )`, + errors: [ { messageId: 'noPlaceholdersOnly' } ], + }, + { + code: `__( '%s%s' )`, + errors: [ { messageId: 'noPlaceholdersOnly' } ], + }, + { + code: `_x( '%1$s' )`, + errors: [ { messageId: 'noPlaceholdersOnly' } ], + }, + { + code: `_n( '%s', '%s', number)`, + errors: [ + { messageId: 'noPlaceholdersOnly' }, + { messageId: 'noPlaceholdersOnly' }, + ], + }, + ], +} ); diff --git a/packages/eslint-plugin/rules/__tests__/i18n-no-variables.js b/packages/eslint-plugin/rules/__tests__/i18n-no-variables.js new file mode 100644 index 00000000000000..1ee322944ef9fd --- /dev/null +++ b/packages/eslint-plugin/rules/__tests__/i18n-no-variables.js @@ -0,0 +1,92 @@ +/** + * External dependencies + */ +import { RuleTester } from 'eslint'; + +/** + * Internal dependencies + */ +import rule from '../i18n-no-variables'; + +const ruleTester = new RuleTester( { + parserOptions: { + ecmaVersion: 6, + }, +} ); + +ruleTester.run( 'i18n-no-variables', rule, { + valid: [ + { + code: `__( 'Hello World' )`, + }, + { + code: `__( 'Hello' + 'World' )`, + }, + { + code: `_x( 'Hello World', 'context' )`, + }, + { + code: `var number = ''; _n( 'Singular', 'Plural', number)`, + }, + { + code: `var number = ''; _nx( 'Singular', 'Plural', number, 'context' )`, + }, + { + code: `__( 'Hello World', 'foo' )`, + }, + { + code: `_x( 'Hello World', 'context', 'foo' )`, + }, + { + code: `var number = ''; _n( 'Singular', 'Plural', number, 'foo' )`, + }, + { + code: `var number = ''; _nx( 'Singular', 'Plural', number, 'context', 'foo' )`, + }, + { + code: `i18n.__( 'Hello World' )`, + }, + ], + invalid: [ + { + code: `__(foo)`, + errors: [ { messageId: 'invalidArgument' } ], + }, + { + code: '__(`Hello ${foo}`)', + errors: [ { messageId: 'invalidArgument' } ], + }, + { + code: `_x(foo, 'context' )`, + errors: [ { messageId: 'invalidArgument' } ], + }, + { + code: `_x( 'Hello World', bar)`, + errors: [ { messageId: 'invalidArgument' } ], + }, + { + code: `var number = ''; _n(foo,'Plural', number)`, + errors: [ { messageId: 'invalidArgument' } ], + }, + { + code: `var number = ''; _n( 'Singular', bar, number)`, + errors: [ { messageId: 'invalidArgument' } ], + }, + { + code: `var number = ''; _nx(foo, 'Plural', number, 'context' )`, + errors: [ { messageId: 'invalidArgument' } ], + }, + { + code: `var number = ''; _nx( 'Singular', bar, number, 'context' )`, + errors: [ { messageId: 'invalidArgument' } ], + }, + { + code: `var number = ''; _nx( 'Singular', 'Plural', number, baz)`, + errors: [ { messageId: 'invalidArgument' } ], + }, + { + code: `i18n.__(foo)`, + errors: [ { messageId: 'invalidArgument' } ], + }, + ], +} ); diff --git a/packages/eslint-plugin/rules/__tests__/i18n-text-domain.js b/packages/eslint-plugin/rules/__tests__/i18n-text-domain.js new file mode 100644 index 00000000000000..1212c90d998ed7 --- /dev/null +++ b/packages/eslint-plugin/rules/__tests__/i18n-text-domain.js @@ -0,0 +1,170 @@ +/** + * External dependencies + */ +import { RuleTester } from 'eslint'; + +/** + * Internal dependencies + */ +import rule from '../i18n-text-domain'; + +const ruleTester = new RuleTester( { + parserOptions: { + ecmaVersion: 6, + }, +} ); + +ruleTester.run( 'i18n-text-domain', rule, { + valid: [ + { + code: `__( 'Hello World' )`, + options: [ { allowedTextDomain: 'default' } ], + }, + { + code: `_x( 'Hello World', 'context' )`, + options: [ { allowedTextDomain: 'default' } ], + }, + { + code: `var number = ''; _n( 'Singular', 'Plural', number )`, + options: [ { allowedTextDomain: 'default' } ], + }, + { + code: `var number = ''; _nx( 'Singular', 'Plural', number, 'context' )`, + options: [ { allowedTextDomain: 'default' } ], + }, + { + code: `__( 'Hello World', 'foo' )`, + options: [ { allowedTextDomain: 'foo' } ], + }, + { + code: `_x( 'Hello World', 'context', 'foo' )`, + options: [ { allowedTextDomain: 'foo' } ], + }, + { + code: `var number = ''; _n( 'Singular', 'Plural', number, 'foo' )`, + options: [ { allowedTextDomain: 'foo' } ], + }, + { + code: `var number = ''; _nx( 'Singular', 'Plural', number, 'context', 'foo' )`, + options: [ { allowedTextDomain: 'foo' } ], + }, + { + code: `i18n.__( 'Hello World' )`, + options: [ { allowedTextDomain: 'default' } ], + }, + ], + invalid: [ + { + code: `__( 'Hello World' )`, + output: `__( 'Hello World', 'foo' )`, + options: [ { allowedTextDomain: 'foo' } ], + errors: [ { messageId: 'missing' } ], + }, + { + code: `_x( 'Hello World', 'context' )`, + output: `_x( 'Hello World', 'context', 'foo' )`, + options: [ { allowedTextDomain: 'foo' } ], + errors: [ { messageId: 'missing' } ], + }, + { + code: `var number = ''; _n( 'Singular', 'Plural', number )`, + output: `var number = ''; _n( 'Singular', 'Plural', number, 'foo' )`, + options: [ { allowedTextDomain: 'foo' } ], + errors: [ { messageId: 'missing' } ], + }, + { + code: `var number = ''; _nx( 'Singular', 'Plural', number, 'context' )`, + output: `var number = ''; _nx( 'Singular', 'Plural', number, 'context', 'foo' )`, + options: [ { allowedTextDomain: 'foo' } ], + errors: [ { messageId: 'missing' } ], + }, + { + code: `__( 'Hello World', 'bar' )`, + output: `__( 'Hello World', 'foo' )`, + options: [ { allowedTextDomain: 'foo' } ], + errors: [ { messageId: 'invalidValue' } ], + }, + { + code: `_x( 'Hello World', 'context', 'bar' )`, + output: `_x( 'Hello World', 'context', 'foo' )`, + options: [ { allowedTextDomain: 'foo' } ], + errors: [ { messageId: 'invalidValue' } ], + }, + { + code: `var number = ''; _n( 'Singular', 'Plural', number, 'bar' )`, + output: `var number = ''; _n( 'Singular', 'Plural', number, 'foo' )`, + options: [ { allowedTextDomain: 'foo' } ], + errors: [ { messageId: 'invalidValue' } ], + }, + { + code: `var number = ''; _nx( 'Singular', 'Plural', number, 'context', 'bar' )`, + output: `var number = ''; _nx( 'Singular', 'Plural', number, 'context', 'foo' )`, + options: [ { allowedTextDomain: 'foo' } ], + errors: [ { messageId: 'invalidValue' } ], + }, + { + code: `var value = ''; __( 'Hello World', value )`, + errors: [ { messageId: 'invalidType' } ], + }, + { + code: `var value = ''; _x( 'Hello World', 'context', value )`, + errors: [ { messageId: 'invalidType' } ], + }, + { + code: `var value = ''; var number = ''; _n( 'Singular', 'Plural', number, value )`, + errors: [ { messageId: 'invalidType' } ], + }, + { + code: `var value = ''; var number = ''; _nx( 'Singular', 'Plural', number, 'context', value )`, + errors: [ { messageId: 'invalidType' } ], + }, + { + code: `__( 'Hello World', 'default' )`, + output: `__( 'Hello World' )`, + options: [ { allowedTextDomain: 'default' } ], + errors: [ { messageId: 'unnecessaryDefault' } ], + }, + { + code: `__( 'default', 'default' )`, + output: `__( 'default' )`, + options: [ { allowedTextDomain: 'default' } ], + errors: [ { messageId: 'unnecessaryDefault' } ], + }, + { + code: `_x( 'Hello World', 'context', 'default' )`, + output: `_x( 'Hello World', 'context' )`, + options: [ { allowedTextDomain: 'default' } ], + errors: [ { messageId: 'unnecessaryDefault' } ], + }, + { + code: `var number = ''; _n( 'Singular', 'Plural', number, 'default' )`, + output: `var number = ''; _n( 'Singular', 'Plural', number )`, + options: [ { allowedTextDomain: 'default' } ], + errors: [ { messageId: 'unnecessaryDefault' } ], + }, + { + code: `var number = ''; _nx( 'Singular', 'Plural', number, 'context', 'default' )`, + output: `var number = ''; _nx( 'Singular', 'Plural', number, 'context' )`, + options: [ { allowedTextDomain: 'default' } ], + errors: [ { messageId: 'unnecessaryDefault' } ], + }, + { + code: `i18n.__( 'Hello World' )`, + output: `i18n.__( 'Hello World', 'foo' )`, + options: [ { allowedTextDomain: 'foo' } ], + errors: [ { messageId: 'missing' } ], + }, + { + code: `__( 'Hello World' )`, + output: `__( 'Hello World', 'foo' )`, + options: [ { allowedTextDomain: [ 'foo' ] } ], + errors: [ { messageId: 'missing' } ], + }, + { + code: `__( 'Hello World' )`, + output: `__( 'Hello World' )`, + options: [ { allowedTextDomain: [ 'foo', 'bar' ] } ], + errors: [ { messageId: 'missing' } ], + }, + ], +} ); diff --git a/packages/eslint-plugin/rules/__tests__/i18n-translator-comments.js b/packages/eslint-plugin/rules/__tests__/i18n-translator-comments.js new file mode 100644 index 00000000000000..df59a9bbe07083 --- /dev/null +++ b/packages/eslint-plugin/rules/__tests__/i18n-translator-comments.js @@ -0,0 +1,84 @@ +/** + * External dependencies + */ +import { RuleTester } from 'eslint'; + +/** + * Internal dependencies + */ +import rule from '../i18n-translator-comments'; + +const ruleTester = new RuleTester( { + parserOptions: { + ecmaVersion: 6, + }, +} ); + +ruleTester.run( 'i18n-translator-comments', rule, { + valid: [ + { + code: ` +// translators: %s: Color +sprintf( __( 'Color: %s' ), color );`, + }, + { + code: ` +sprintf( + // translators: %s: Address. + __( 'Address: %s' ), + address +);`, + }, + { + code: ` +// translators: %s: Color +i18n.sprintf( i18n.__( 'Color: %s' ), color );`, + }, + ], + invalid: [ + { + code: ` +sprintf( __( 'Color: %s' ), color );`, + errors: [ { messageId: 'missing' } ], + }, + { + code: ` +sprintf( + __( 'Address: %s' ), + address +);`, + errors: [ { messageId: 'missing' } ], + }, + { + code: ` +// translators: %s: Name +var name = ''; +sprintf( __( 'Name: %s' ), name );`, + errors: [ { messageId: 'missing' } ], + }, + { + code: ` +// translators: %s: Surname +console.log( + sprintf( __( 'Surname: %s' ), name ) +);`, + errors: [ { messageId: 'missing' } ], + }, + { + code: ` +// translators: %s: Preference +console.log( + sprintf( + __( 'Preference: %s' ), + preference + ) +);`, + errors: [ { messageId: 'missing' } ], + }, + { + code: ` +i18n.sprintf( i18n.__( 'Color: %s' ), color );`, + errors: [ { messageId: 'missing' } ], + }, + ], +} ); diff --git a/packages/eslint-plugin/rules/__tests__/no-unused-vars-before-return.js b/packages/eslint-plugin/rules/__tests__/no-unused-vars-before-return.js index 291559e956f3ec..fe909e6c717303 100644 --- a/packages/eslint-plugin/rules/__tests__/no-unused-vars-before-return.js +++ b/packages/eslint-plugin/rules/__tests__/no-unused-vars-before-return.js @@ -11,6 +11,9 @@ import rule from '../no-unused-vars-before-return'; const ruleTester = new RuleTester( { parserOptions: { ecmaVersion: 6, + ecmaFeatures: { + jsx: true, + }, }, } ); @@ -50,6 +53,13 @@ function example() { }`, options: [ { excludePattern: '^do' } ], }, + { + code: ` +function MyComponent() { + const Foo = getSomeComponent(); + return <Foo />; +}`, + }, ], invalid: [ { @@ -104,5 +114,24 @@ function example() { }, ], }, + { + code: ` +function example() { + const foo = doSomeCostlyOperation(); + const bar = anotherCostlyOperation( foo ); + if ( number > 10 ) { + return number + 1; + } + + return number + foo + bar; +}`, + options: [ { excludePattern: '^do' } ], + errors: [ + { + message: + 'Variables should not be assigned until just prior its first reference. An early return statement may leave this variable unused.', + }, + ], + }, ], } ); diff --git a/packages/eslint-plugin/rules/__tests__/valid-sprintf.js b/packages/eslint-plugin/rules/__tests__/valid-sprintf.js index 119653220b3c0a..9b2b7de255d47b 100644 --- a/packages/eslint-plugin/rules/__tests__/valid-sprintf.js +++ b/packages/eslint-plugin/rules/__tests__/valid-sprintf.js @@ -19,6 +19,9 @@ ruleTester.run( 'valid-sprintf', rule, { { code: `sprintf( '%s', 'substitute' )`, }, + { + code: `sprintf( '%1$d%%', 500 )`, + }, { code: `sprintf( __( '%s' ), 'substitute' )`, }, @@ -37,76 +40,92 @@ ruleTester.run( 'valid-sprintf', rule, { { code: `var value = ''; sprintf( value, 'substitute' )`, }, + { + code: ` +sprintf( + /* translators: 1: number of blocks. 2: average rating. */ + _n( + 'This author has %1$d block, with an average rating of %2$d.', + 'This author has %1$d blocks, with an average rating of %2$d.', + authorBlockCount + ), + authorBlockCount, + authorBlockRating +);`, + }, + { + code: `i18n.sprintf( '%s', 'substitute' )`, + }, + { + code: `i18n.sprintf( i18n.__( '%s' ), 'substitute' )`, + }, + { + code: `sprintf( ...args )`, + }, + { + code: `sprintf( '%1$s %2$s', 'foo', 'bar' )`, + }, + { + code: `sprintf( '%(greeting)s', 'Hello' )`, + }, + { + code: `sprintf( '%(greeting)s %(toWhom)s', 'Hello', 'World' )`, + }, ], invalid: [ { code: `sprintf()`, - errors: [ - { message: 'sprintf must be called with a format string' }, - ], + errors: [ { messageId: 'noFormatString' } ], }, { code: `sprintf( '%s' )`, - errors: [ - { - message: - 'sprintf must be called with placeholder value argument(s)', - }, - ], + errors: [ { messageId: 'noPlaceholderArgs' } ], }, { code: `sprintf( 1, 'substitute' )`, - errors: [ - { - message: - 'sprintf must be called with a valid format string', - }, - ], + errors: [ { messageId: 'invalidFormatString' } ], }, { code: `sprintf( [], 'substitute' )`, - errors: [ - { - message: - 'sprintf must be called with a valid format string', - }, - ], + errors: [ { messageId: 'invalidFormatString' } ], }, { code: `sprintf( '%%', 'substitute' )`, - errors: [ - { - message: - 'sprintf format string must contain at least one placeholder', - }, - ], + errors: [ { messageId: 'noPlaceholders' } ], }, { code: `sprintf( __( '%%' ), 'substitute' )`, - errors: [ - { - message: - 'sprintf format string must contain at least one placeholder', - }, - ], + errors: [ { messageId: 'noPlaceholders' } ], }, { code: `sprintf( _n( '%s', '' ), 'substitute' )`, - errors: [ - { - message: - 'sprintf format string options must have the same number of placeholders', - }, - ], + errors: [ { messageId: 'placeholderMismatch' } ], }, { code: `sprintf( _n( '%s', '%s %s' ), 'substitute' )`, - errors: [ - { - message: - 'sprintf format string options must have the same number of placeholders', - }, - ], + errors: [ { messageId: 'placeholderMismatch' } ], + }, + { + code: ` +sprintf( + /* translators: 1: number of blocks. 2: average rating. */ + _n( + 'This author has %d block, with an average rating of %d.', + 'This author has %d blocks, with an average rating of %d.', + authorBlockCount + ), + authorBlockCount, + authorBlockRating +);`, + errors: [ { messageId: 'noOrderedPlaceholders' } ], + }, + { + code: `i18n.sprintf()`, + errors: [ { messageId: 'noFormatString' } ], + }, + { + code: `i18n.sprintf( i18n.__( '%%' ), 'substitute' )`, + errors: [ { messageId: 'noPlaceholders' } ], }, ], } ); diff --git a/packages/eslint-plugin/rules/i18n-ellipsis.js b/packages/eslint-plugin/rules/i18n-ellipsis.js new file mode 100644 index 00000000000000..8e1b5eabf9b5e5 --- /dev/null +++ b/packages/eslint-plugin/rules/i18n-ellipsis.js @@ -0,0 +1,98 @@ +/** + * Internal dependencies + */ +const { + TRANSLATION_FUNCTIONS, + getTextContentFromNode, + getTranslateFunctionName, + getTranslateFunctionArgs, +} = require( '../utils' ); + +const THREE_DOTS = '...'; +const ELLIPSIS = '…'; + +function replaceThreeDotsWithEllipsis( string ) { + return string.replace( /\.\.\./g, ELLIPSIS ); +} + +// see eslint-plugin-wpcalypso. +function makeFixerFunction( arg ) { + return ( fixer ) => { + switch ( arg.type ) { + case 'TemplateLiteral': + return arg.quasis.reduce( ( fixes, quasi ) => { + if ( + 'TemplateElement' === quasi.type && + quasi.value.raw.includes( THREE_DOTS ) + ) { + fixes.push( + fixer.replaceTextRange( + [ quasi.start, quasi.end ], + replaceThreeDotsWithEllipsis( quasi.value.raw ) + ) + ); + } + return fixes; + }, [] ); + + case 'Literal': + return [ + fixer.replaceText( + arg, + replaceThreeDotsWithEllipsis( arg.raw ) + ), + ]; + + case 'BinaryExpression': + return [ + ...makeFixerFunction( arg.left )( fixer ), + ...makeFixerFunction( arg.right )( fixer ), + ]; + } + }; +} + +module.exports = { + meta: { + type: 'problem', + schema: [], + messages: { + foundThreeDots: 'Use ellipsis character (…) in place of three dots', + }, + fixable: 'code', + }, + create( context ) { + return { + CallExpression( node ) { + const { callee, arguments: args } = node; + + const functionName = getTranslateFunctionName( callee ); + + if ( ! TRANSLATION_FUNCTIONS.has( functionName ) ) { + return; + } + + const candidates = getTranslateFunctionArgs( + functionName, + args + ); + + for ( const arg of candidates ) { + const argumentString = getTextContentFromNode( arg ); + if ( + ! argumentString || + ! argumentString.includes( THREE_DOTS ) + ) { + continue; + } + + context.report( { + node, + messageId: 'foundThreeDots', + fix: makeFixerFunction( arg ), + } ); + } + }, + }; + }, +}; diff --git a/packages/eslint-plugin/rules/i18n-no-collapsible-whitespace.js b/packages/eslint-plugin/rules/i18n-no-collapsible-whitespace.js new file mode 100644 index 00000000000000..1d34472bc7b4a7 --- /dev/null +++ b/packages/eslint-plugin/rules/i18n-no-collapsible-whitespace.js @@ -0,0 +1,74 @@ +/** + * Internal dependencies + */ +const { + TRANSLATION_FUNCTIONS, + getTextContentFromNode, + getTranslateFunctionName, + getTranslateFunctionArgs, +} = require( '../utils' ); + +const PROBLEMS_BY_CHAR_CODE = { + 9: '\\t', + 10: '\\n', + 13: '\\r', + 32: 'consecutive spaces', +}; + +module.exports = { + meta: { + type: 'problem', + schema: [], + messages: { + noCollapsibleWhitespace: + 'Translations should not contain collapsible whitespace{{problem}}', + }, + }, + create( context ) { + return { + CallExpression( node ) { + const { callee, arguments: args } = node; + + const functionName = getTranslateFunctionName( callee ); + + if ( ! TRANSLATION_FUNCTIONS.has( functionName ) ) { + return; + } + + const candidates = getTranslateFunctionArgs( + functionName, + args + ); + + for ( const arg of candidates ) { + const argumentString = getTextContentFromNode( arg ); + if ( ! argumentString ) { + continue; + } + + const collapsibleWhitespace = argumentString.match( + /(\n|\t|\r| {2})/ + ); + + if ( ! collapsibleWhitespace ) { + continue; + } + + const problem = + PROBLEMS_BY_CHAR_CODE[ + collapsibleWhitespace[ 0 ].charCodeAt( 0 ) + ]; + const problemString = problem ? ` (${ problem })` : ''; + + context.report( { + node, + messageId: 'noCollapsibleWhitespace', + data: { + problem: problemString, + }, + } ); + } + }, + }; + }, +}; diff --git a/packages/eslint-plugin/rules/i18n-no-placeholders-only.js b/packages/eslint-plugin/rules/i18n-no-placeholders-only.js new file mode 100644 index 00000000000000..3cc2b3dc34fb0f --- /dev/null +++ b/packages/eslint-plugin/rules/i18n-no-placeholders-only.js @@ -0,0 +1,59 @@ +/** + * Internal dependencies + */ +const { + TRANSLATION_FUNCTIONS, + REGEXP_SPRINTF_PLACEHOLDER, + getTextContentFromNode, + getTranslateFunctionName, + getTranslateFunctionArgs, +} = require( '../utils' ); + +module.exports = { + meta: { + type: 'problem', + schema: [], + messages: { + noPlaceholdersOnly: + 'Translatable strings should not contain nothing but placeholders', + }, + }, + create( context ) { + return { + CallExpression( node ) { + const { callee, arguments: args } = node; + + const functionName = getTranslateFunctionName( callee ); + + if ( ! TRANSLATION_FUNCTIONS.has( functionName ) ) { + return; + } + + const candidates = getTranslateFunctionArgs( + functionName, + args + ); + + for ( const arg of candidates ) { + const argumentString = getTextContentFromNode( arg ); + if ( ! argumentString ) { + continue; + } + + const modifiedString = argumentString + .replace( /%%/g, 'VALID_ESCAPED_PERCENTAGE_SIGN' ) + .replace( REGEXP_SPRINTF_PLACEHOLDER, '' ); + + if ( modifiedString.length > 0 ) { + continue; + } + + context.report( { + node, + messageId: 'noPlaceholdersOnly', + } ); + } + }, + }; + }, +}; diff --git a/packages/eslint-plugin/rules/i18n-no-variables.js b/packages/eslint-plugin/rules/i18n-no-variables.js new file mode 100644 index 00000000000000..c942ba440a7676 --- /dev/null +++ b/packages/eslint-plugin/rules/i18n-no-variables.js @@ -0,0 +1,66 @@ +/** + * Internal dependencies + */ +const { + TRANSLATION_FUNCTIONS, + getTranslateFunctionName, + getTranslateFunctionArgs, +} = require( '../utils' ); + +function isAcceptableLiteralNode( node ) { + if ( 'BinaryExpression' === node.type ) { + return ( + '+' === node.operator && + isAcceptableLiteralNode( node.left ) && + isAcceptableLiteralNode( node.right ) + ); + } + + if ( 'TemplateLiteral' === node.type ) { + // Backticks are fine, but if there's any interpolation in it, + // that's a problem + return node.expressions.length === 0; + } + + return 'Literal' === node.type; +} + +module.exports = { + meta: { + type: 'problem', + schema: [], + messages: { + invalidArgument: + 'Translate function arguments must be string literals.', + }, + }, + create( context ) { + return { + CallExpression( node ) { + const { callee, arguments: args } = node; + + const functionName = getTranslateFunctionName( callee ); + + if ( ! TRANSLATION_FUNCTIONS.has( functionName ) ) { + return; + } + + const candidates = getTranslateFunctionArgs( + functionName, + args + ); + + for ( const arg of candidates ) { + if ( isAcceptableLiteralNode( arg ) ) { + continue; + } + + context.report( { + node, + messageId: 'invalidArgument', + } ); + } + }, + }; + }, +}; diff --git a/packages/eslint-plugin/rules/i18n-text-domain.js b/packages/eslint-plugin/rules/i18n-text-domain.js new file mode 100644 index 00000000000000..94b0619372d547 --- /dev/null +++ b/packages/eslint-plugin/rules/i18n-text-domain.js @@ -0,0 +1,158 @@ +/** + * Internal dependencies + */ +const { + TRANSLATION_FUNCTIONS, + getTranslateFunctionName, +} = require( '../utils' ); + +/** + * Returns the text domain passed to the given translation function. + * + * @param {string} functionName Translation function name. + * @param {Array} args Function arguments. + * @return {undefined|*} Text domain argument. + */ +function getTextDomain( functionName, args ) { + switch ( functionName ) { + case '__': + return args[ 1 ]; + case '_x': + return args[ 2 ]; + case '_n': + return args[ 3 ]; + case '_nx': + return args[ 4 ]; + default: + return undefined; + } +} + +module.exports = { + meta: { + type: 'problem', + schema: [ + { + type: 'object', + properties: { + // Supports a single string as the majority use case, + // but also an array of text domains. + allowedTextDomain: { + anyOf: [ + { + type: 'array', + items: { + type: 'string', + }, + uniqueItems: true, + }, + { + type: 'string', + default: 'default', + }, + ], + }, + }, + additionalProperties: false, + }, + ], + messages: { + invalidValue: "Invalid text domain '{{ textDomain }}'", + invalidType: 'Text domain is not a string literal', + unnecessaryDefault: 'Unnecessary default text domain', + missing: 'Missing text domain', + useAllowedValue: + 'Use one of the whitelisted text domains: {{ textDomains }}', + }, + fixable: 'code', + }, + create( context ) { + const options = context.options[ 0 ] || {}; + const { allowedTextDomain = 'default' } = options; + const allowedTextDomains = Array.isArray( allowedTextDomain ) + ? allowedTextDomain + : [ allowedTextDomain ]; + const canFixTextDomain = allowedTextDomains.length === 1; + const allowDefault = allowedTextDomains.includes( 'default' ); + + return { + CallExpression( node ) { + const { callee, arguments: args } = node; + + const functionName = getTranslateFunctionName( callee ); + + if ( ! TRANSLATION_FUNCTIONS.has( functionName ) ) { + return; + } + + const textDomain = getTextDomain( functionName, args ); + + if ( textDomain === undefined ) { + if ( ! allowDefault ) { + const addMissingTextDomain = ( fixer ) => { + const lastArg = args[ args.length - 1 ]; + return fixer.insertTextAfter( + lastArg, + `, '${ allowedTextDomains[ 0 ] }'` + ); + }; + + context.report( { + node, + messageId: 'missing', + fix: canFixTextDomain ? addMissingTextDomain : null, + } ); + } + return; + } + + const { type, value, range } = textDomain; + + if ( type !== 'Literal' ) { + context.report( { + node, + messageId: 'invalidType', + } ); + return; + } + + if ( 'default' === value && allowDefault ) { + const removeDefaultTextDomain = ( fixer ) => { + const previousArgIndex = args.indexOf( textDomain ) - 1; + const previousArg = args[ previousArgIndex ]; + return fixer.removeRange( [ + previousArg.range[ 1 ], + range[ 1 ], + ] ); + }; + + context.report( { + node, + messageId: 'unnecessaryDefault', + fix: removeDefaultTextDomain, + } ); + return; + } + + if ( ! allowedTextDomains.includes( value ) ) { + const replaceTextDomain = ( fixer ) => { + return fixer.replaceTextRange( + // account for quotes. + [ range[ 0 ] + 1, range[ 1 ] - 1 ], + allowedTextDomains[ 0 ] + ); + }; + + context.report( { + node, + messageId: 'invalidValue', + data: { + textDomain: value, + }, + fix: canFixTextDomain ? replaceTextDomain : null, + } ); + } + }, + }; + }, +}; diff --git a/packages/eslint-plugin/rules/i18n-translator-comments.js b/packages/eslint-plugin/rules/i18n-translator-comments.js new file mode 100644 index 00000000000000..86d57449dc0547 --- /dev/null +++ b/packages/eslint-plugin/rules/i18n-translator-comments.js @@ -0,0 +1,112 @@ +/** + * Internal dependencies + */ +const { + TRANSLATION_FUNCTIONS, + REGEXP_SPRINTF_PLACEHOLDER, + getTranslateFunctionName, + getTranslateFunctionArgs, + getTextContentFromNode, +} = require( '../utils' ); + +module.exports = { + meta: { + type: 'problem', + messages: { + missing: + 'Translation function with placeholders is missing preceding translator comment', + }, + }, + create( context ) { + return { + CallExpression( node ) { + const { + callee, + loc: { + start: { line: currentLine }, + }, + parent, + arguments: args, + } = node; + + const functionName = getTranslateFunctionName( callee ); + + if ( ! TRANSLATION_FUNCTIONS.has( functionName ) ) { + return; + } + + const candidates = getTranslateFunctionArgs( + functionName, + args + ).map( getTextContentFromNode ); + + if ( candidates.filter( Boolean ).length === 0 ) { + return; + } + + const hasPlaceholders = candidates.some( ( candidate ) => + REGEXP_SPRINTF_PLACEHOLDER.test( candidate ) + ); + // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test#Using_test()_on_a_regex_with_the_global_flag. + REGEXP_SPRINTF_PLACEHOLDER.lastIndex = 0; + + if ( ! hasPlaceholders ) { + return; + } + + const comments = context.getCommentsBefore( node ).slice(); + + let parentNode = parent; + + /** + * Loop through all parent nodes and get their preceding comments as well. + * + * This way we can gather comments that are not directly preceding the translation + * function call, but are just on the line above it. This case is commonly supported + * by string extraction tools like WP-CLI's i18n command. + */ + while ( + parentNode && + parentNode.type !== 'Program' && + Math.abs( parentNode.loc.start.line - currentLine ) <= 1 + ) { + comments.push( ...context.getCommentsBefore( parentNode ) ); + parentNode = parentNode.parent; + } + + for ( const comment of comments ) { + const { + value: commentText, + loc: { + start: { line: commentLine }, + }, + } = comment; + + /* + Skip cases like this: + + // translators: %s: Preference + console.log( + sprintf( + __( 'Preference: %s' ), + preference + ) + ); + */ + if ( Math.abs( commentLine - currentLine ) > 1 ) { + break; + } + + if ( /translators:\s*\S+/i.test( commentText ) ) { + return; + } + } + + context.report( { + node, + messageId: 'missing', + } ); + }, + }; + }, +}; diff --git a/packages/eslint-plugin/rules/no-unused-vars-before-return.js b/packages/eslint-plugin/rules/no-unused-vars-before-return.js index 1a4cbb7d91c151..1394de7f4a67c1 100644 --- a/packages/eslint-plugin/rules/no-unused-vars-before-return.js +++ b/packages/eslint-plugin/rules/no-unused-vars-before-return.js @@ -1,4 +1,33 @@ -module.exports = { +/** @typedef {import('eslint').Scope.Scope} ESLintScope */ +/** @typedef {import('eslint').Rule.RuleContext} ESLintRuleContext */ +/** @typedef {import('estree').Node} ESTreeNode */ + +/** + * Mapping of function scope objects to a set of identified JSX identifiers + * within that scope. + * + * @type {WeakMap<ESLintScope,Set<ESTreeNode>>} + */ +const FUNCTION_SCOPE_JSX_IDENTIFIERS = new WeakMap(); + +/** + * Returns the closest function scope for the current ESLint context object, or + * undefined if it cannot be determined. + * + * @param {ESLintRuleContext} context ESLint context object. + * + * @return {ESLintScope|undefined} Function scope, if known. + */ +function getClosestFunctionScope( context ) { + let functionScope = context.getScope(); + while ( functionScope.type !== 'function' && functionScope.upper ) { + functionScope = functionScope.upper; + } + + return functionScope; +} + +module.exports = /** @type {import('eslint').Rule} */ ( { meta: { type: 'problem', schema: [ @@ -13,6 +42,9 @@ module.exports = { }, ], }, + /** + * @param {ESLintRuleContext} context Rule context. + */ create( context ) { const options = context.options[ 0 ] || {}; const { excludePattern } = options; @@ -36,15 +68,27 @@ module.exports = { } return { - ReturnStatement( node ) { - let functionScope = context.getScope(); - while ( - functionScope.type !== 'function' && - functionScope.upper - ) { - functionScope = functionScope.upper; + JSXIdentifier( node ) { + // Currently, a scope's variable references does not include JSX + // identifiers. Account for this by visiting JSX identifiers + // first, and tracking them in a map per function scope, which + // is later merged with the known variable references. + const functionScope = getClosestFunctionScope( context ); + if ( ! functionScope ) { + return; + } + + if ( ! FUNCTION_SCOPE_JSX_IDENTIFIERS.has( functionScope ) ) { + FUNCTION_SCOPE_JSX_IDENTIFIERS.set( + functionScope, + new Set() + ); } + FUNCTION_SCOPE_JSX_IDENTIFIERS.get( functionScope ).add( node ); + }, + 'ReturnStatement:exit'( node ) { + const functionScope = getClosestFunctionScope( context ); if ( ! functionScope ) { return; } @@ -74,16 +118,27 @@ module.exports = { declaratorCandidate.node.init.callee.name ) ) { - return; + continue; } // The first entry in `references` is the declaration // itself, which can be ignored. - const isUsedBeforeReturn = variable.references + const identifiers = variable.references .slice( 1 ) - .some( ( reference ) => { - return reference.identifier.end < node.end; - } ); + .map( ( reference ) => reference.identifier ); + + // Merge with any JSX identifiers in scope, if any. + if ( FUNCTION_SCOPE_JSX_IDENTIFIERS.has( functionScope ) ) { + const jsxIdentifiers = FUNCTION_SCOPE_JSX_IDENTIFIERS.get( + functionScope + ); + + identifiers.push( ...jsxIdentifiers ); + } + + const isUsedBeforeReturn = identifiers.some( + ( identifier ) => identifier.end < node.end + ); if ( isUsedBeforeReturn ) { continue; @@ -98,4 +153,4 @@ module.exports = { }, }; }, -}; +} ); diff --git a/packages/eslint-plugin/rules/valid-sprintf.js b/packages/eslint-plugin/rules/valid-sprintf.js index 73101d12b7d676..593ea11b564a02 100644 --- a/packages/eslint-plugin/rules/valid-sprintf.js +++ b/packages/eslint-plugin/rules/valid-sprintf.js @@ -1,68 +1,63 @@ /** - * Regular expression matching the presence of a printf format string - * placeholder. This naive pattern which does not validate the format. - * - * @type {RegExp} + * Internal dependencies */ -const REGEXP_PLACEHOLDER = /%[^%]/g; - -/** - * Given a function name and array of argument Node values, returns all - * possible string results from the corresponding translate function, or - * undefined if the function is not a translate function. - * - * @param {string} functionName Function name. - * @param {espree.Node[]} args Espree argument Node objects. - * - * @return {?Array<string>} All possible translate function string results. - */ -function getTranslateStrings( functionName, args ) { - switch ( functionName ) { - case '__': - case '_x': - args = args.slice( 0, 1 ); - break; - - case '_n': - case '_nx': - args = args.slice( 0, 2 ); - break; - - default: - return; - } - - return args - .filter( ( arg ) => arg.type === 'Literal' ) - .map( ( arg ) => arg.value ); -} +const { + REGEXP_SPRINTF_PLACEHOLDER, + REGEXP_SPRINTF_PLACEHOLDER_UNORDERED, + getTranslateFunctionName, + getTranslateFunctionArgs, + getTextContentFromNode, +} = require( '../utils' ); module.exports = { meta: { type: 'problem', schema: [], + messages: { + noFormatString: 'sprintf must be called with a format string', + invalidFormatString: + 'sprintf must be called with a valid format string', + noPlaceholderArgs: + 'sprintf must be called with placeholder value argument(s)', + noPlaceholders: + 'sprintf format string must contain at least one placeholder', + placeholderMismatch: + 'sprintf format string options must have the same number of placeholders', + noOrderedPlaceholders: + 'Multiple sprintf placeholders should be ordered. Mix of ordered and non-ordered placeholders found.', + }, }, create( context ) { return { CallExpression( node ) { const { callee, arguments: args } = node; - if ( callee.name !== 'sprintf' ) { + + const functionName = + callee.property && callee.property.name + ? callee.property.name + : callee.name; + + if ( functionName !== 'sprintf' ) { return; } if ( ! args.length ) { - context.report( + context.report( { node, - 'sprintf must be called with a format string' - ); + messageId: 'noFormatString', + } ); return; } if ( args.length < 2 ) { - context.report( + if ( args[ 0 ].type === 'SpreadElement' ) { + return; + } + + context.report( { node, - 'sprintf must be called with placeholder value argument(s)' - ); + messageId: 'noPlaceholderArgs', + } ); return; } @@ -77,17 +72,22 @@ module.exports = { break; case 'CallExpression': + const argFunctionName = getTranslateFunctionName( + args[ 0 ].callee + ); + // All possible options (arguments) from a translate // function must be valid. - candidates = getTranslateStrings( - args[ 0 ].callee.name, - args[ 0 ].arguments - ); + candidates = getTranslateFunctionArgs( + argFunctionName, + args[ 0 ].arguments, + false + ).map( getTextContentFromNode ); // An unknown function call may produce a valid string // value. Ideally its result is verified, but this is // not straight-forward to implement. Thus, bail. - if ( candidates === undefined ) { + if ( candidates.filter( Boolean ).length === 0 ) { return; } @@ -104,36 +104,61 @@ module.exports = { } if ( ! candidates.length ) { - context.report( + context.report( { node, - 'sprintf must be called with a valid format string' - ); + messageId: 'invalidFormatString', + } ); return; } let numPlaceholders; - for ( let i = 0; i < candidates.length; i++ ) { - const match = candidates[ i ].match( REGEXP_PLACEHOLDER ); + for ( const candidate of candidates ) { + const allMatches = candidate.match( + REGEXP_SPRINTF_PLACEHOLDER + ); // Prioritize placeholder number consistency over matching // placeholder, since it's a more common error to omit a // placeholder from the singular form of pluralization. if ( numPlaceholders !== undefined && - ( ! match || numPlaceholders !== match.length ) + ( ! allMatches || + numPlaceholders !== allMatches.length ) ) { - context.report( + context.report( { node, - 'sprintf format string options must have the same number of placeholders' - ); + messageId: 'placeholderMismatch', + } ); return; } - if ( ! match ) { - context.report( + const unorderedMatches = candidate.match( + REGEXP_SPRINTF_PLACEHOLDER_UNORDERED + ); + + if ( + unorderedMatches && + allMatches && + unorderedMatches.length > 0 && + allMatches.length > 1 && + unorderedMatches.length !== allMatches.length + ) { + context.report( { node, - 'sprintf format string must contain at least one placeholder' - ); + messageId: 'noOrderedPlaceholders', + } ); + return; + } + + // Catch cases where a string only contains %% (escaped percentage sign). + if ( + ! allMatches || + ( allMatches.length === 1 && allMatches[ 0 ] === '%%' ) + ) { + context.report( { + node, + messageId: 'noPlaceholders', + } ); return; } @@ -141,7 +166,7 @@ module.exports = { // Track the number of placeholders discovered in the // string to verify that all other candidate options // have the same number. - numPlaceholders = match.length; + numPlaceholders = allMatches.length; } } }, diff --git a/packages/eslint-plugin/utils/constants.js b/packages/eslint-plugin/utils/constants.js new file mode 100644 index 00000000000000..66ba5b52b63a5b --- /dev/null +++ b/packages/eslint-plugin/utils/constants.js @@ -0,0 +1,60 @@ +/** + * List of translation functions exposed by the `@wordpress/i18n` package. + * + * @type {Set<string>} Translation functions. + */ +const TRANSLATION_FUNCTIONS = new Set( [ '__', '_x', '_n', '_nx' ] ); + +/** + * Regular expression matching format placeholder syntax. + * + * The pattern for matching named arguments is a naive and incomplete matcher + * against valid JavaScript identifier names. + * + * via Mathias Bynens: + * + * >An identifier must start with $, _, or any character in the Unicode + * >categories β€œUppercase letter (Lu)”, β€œLowercase letter (Ll)”, β€œTitlecase + * >letter (Lt)”, β€œModifier letter (Lm)”, β€œOther letter (Lo)”, or β€œLetter + * >number (Nl)”. + * > + * >The rest of the string can contain the same characters, plus any U+200C zero + * >width non-joiner characters, U+200D zero width joiner characters, and + * >characters in the Unicode categories β€œNon-spacing mark (Mn)”, β€œSpacing + * >combining mark (Mc)”, β€œDecimal digit number (Nd)”, or β€œConnector + * >punctuation (Pc)”. + * + * If browser support is constrained to those supporting ES2015, this could be + * made more accurate using the `u` flag: + * + * ``` + * /^[$_\p{L}\p{Nl}][$_\p{L}\p{Nl}\u200C\u200D\p{Mn}\p{Mc}\p{Nd}\p{Pc}]*$/u; + * ``` + * + * @see http://www.pixelbeat.org/programming/gcc/format_specs.html + * @see https://mathiasbynens.be/notes/javascript-identifiers#valid-identifier-names + * + * @type {RegExp} + */ +const REGEXP_SPRINTF_PLACEHOLDER = /%(((\d+)\$)|(\(([$_a-zA-Z][$_a-zA-Z0-9]*)\)))?[ +0#-]*\d*(\.(\d+|\*))?(ll|[lhqL])?([cduxXefgsp%])/g; +// β–² β–² β–² β–² β–² β–² β–² type +// β”‚ β”‚ β”‚ β”‚ β”‚ β”” Length (unsupported) +// β”‚ β”‚ β”‚ β”‚ β”” Precision / max width +// β”‚ β”‚ β”‚ β”” Min width (unsupported) +// β”‚ β”‚ β”” Flags (unsupported) +// β”” Index β”” Name (for named arguments) + +/** + * "Unordered" means there's no position specifier: '%s', not '%2$s'. + * + * @see https://github.com/WordPress/WordPress-Coding-Standards/blob/2f927b0ba2bfcbffaa8f3251c086e109302d6622/WordPress/Sniffs/WP/I18nSniff.php#L62-L81 + * + * @type {RegExp} + */ +const REGEXP_SPRINTF_PLACEHOLDER_UNORDERED = /(?:(?<!%)%[+-]?(?:(?:0|'.)?-?[0-9]*(?:\.(?:[ 0]|'.)?[0-9]+)?|(?:[ ])?-?[0-9]+(?:\.(?:[ 0]|'.)?[0-9]+)?)[bcdeEfFgGosuxX])/; + +module.exports = { + TRANSLATION_FUNCTIONS, + REGEXP_SPRINTF_PLACEHOLDER, + REGEXP_SPRINTF_PLACEHOLDER_UNORDERED, +}; diff --git a/packages/eslint-plugin/utils/get-text-content-from-node.js b/packages/eslint-plugin/utils/get-text-content-from-node.js new file mode 100644 index 00000000000000..672f4f1aee7d4f --- /dev/null +++ b/packages/eslint-plugin/utils/get-text-content-from-node.js @@ -0,0 +1,34 @@ +/** + * Returns the actual text content from an argument passed to a translation function. + * + * @see eslint-plugin-wpcalypso + * + * @param {Object} node A Literal, TemplateLiteral or BinaryExpression (+) node + * @return {string|boolean} The concatenated string or false. + */ +function getTextContentFromNode( node ) { + if ( 'Literal' === node.type ) { + return node.value; + } + + if ( 'BinaryExpression' === node.type && '+' === node.operator ) { + const left = getTextContentFromNode( node.left ); + const right = getTextContentFromNode( node.right ); + + if ( left === false || right === false ) { + return false; + } + + return left + right; + } + + if ( node.type === 'TemplateLiteral' ) { + return node.quasis.map( ( quasis ) => quasis.value.raw ).join( '' ); + } + + return false; +} + +module.exports = { + getTextContentFromNode, +}; diff --git a/packages/eslint-plugin/utils/get-translate-function-args.js b/packages/eslint-plugin/utils/get-translate-function-args.js new file mode 100644 index 00000000000000..2ae5a611bb1b80 --- /dev/null +++ b/packages/eslint-plugin/utils/get-translate-function-args.js @@ -0,0 +1,40 @@ +/** + * Given a function name and array of argument Node values, + * returns all arguments except for text domain and number arguments. + * + * @param {string} functionName Function name. + * @param {espree.Node[]} args Espree argument Node objects. + * @param {boolean} includeContext Whether to include the context argument or not. + * + * @return {espree.Node[]} Translate function arguments. + */ +function getTranslateFunctionArgs( functionName, args, includeContext = true ) { + switch ( functionName ) { + case '__': + // __( text, domain ) -> [ text ]. + return args.slice( 0, 1 ); + + case '_x': + // _x( text, context, domain ) -> [ text, context ]. + return includeContext ? args.slice( 0, 2 ) : args.slice( 0, 1 ); + + case '_n': + // _n( single, plural, number, domain ) -> [ single, plural ]. + return args.slice( 0, 2 ); + + case '_nx': + // _nx( single, plural, number, context, domain ) -> [ single, plural, context ]. + const result = args.slice( 0, 2 ); + if ( includeContext ) { + result.push( args[ 3 ] ); + } + return result; + + default: + return []; + } +} + +module.exports = { + getTranslateFunctionArgs, +}; diff --git a/packages/eslint-plugin/utils/get-translate-function-name.js b/packages/eslint-plugin/utils/get-translate-function-name.js new file mode 100644 index 00000000000000..f62143572c62e6 --- /dev/null +++ b/packages/eslint-plugin/utils/get-translate-function-name.js @@ -0,0 +1,17 @@ +/** + * Get the actual translation function name from a CallExpression callee. + * + * Returns the "__" part from __ or i18n.__. + * + * @param {Object} callee + * @return {string} Function name. + */ +function getTranslateFunctionName( callee ) { + return callee.property && callee.property.name + ? callee.property.name + : callee.name; +} + +module.exports = { + getTranslateFunctionName, +}; diff --git a/packages/eslint-plugin/utils/index.js b/packages/eslint-plugin/utils/index.js new file mode 100644 index 00000000000000..97daaaa3208dd3 --- /dev/null +++ b/packages/eslint-plugin/utils/index.js @@ -0,0 +1,17 @@ +const { + TRANSLATION_FUNCTIONS, + REGEXP_SPRINTF_PLACEHOLDER, + REGEXP_SPRINTF_PLACEHOLDER_UNORDERED, +} = require( './constants' ); +const { getTranslateFunctionArgs } = require( './get-translate-function-args' ); +const { getTextContentFromNode } = require( './get-text-content-from-node' ); +const { getTranslateFunctionName } = require( './get-translate-function-name' ); + +module.exports = { + TRANSLATION_FUNCTIONS, + REGEXP_SPRINTF_PLACEHOLDER, + REGEXP_SPRINTF_PLACEHOLDER_UNORDERED, + getTranslateFunctionArgs, + getTextContentFromNode, + getTranslateFunctionName, +}; diff --git a/packages/format-library/package.json b/packages/format-library/package.json index efade3be5cdaa8..57f0e5e864ee03 100644 --- a/packages/format-library/package.json +++ b/packages/format-library/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/format-library", - "version": "1.14.5", + "version": "1.16.1", "description": "Format library for the WordPress editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -21,7 +21,7 @@ "module": "build-module/index.js", "react-native": "src/index", "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/block-editor": "file:../block-editor", "@wordpress/components": "file:../components", "@wordpress/data": "file:../data", diff --git a/packages/format-library/src/link/inline.js b/packages/format-library/src/link/inline.js index 827e6652e4025a..779bbbf89834fd 100644 --- a/packages/format-library/src/link/inline.js +++ b/packages/format-library/src/link/inline.js @@ -119,15 +119,19 @@ function InlineLinkUI( { } ); if ( isCollapsed( value ) && ! isActive ) { + const newText = nextValue.title || newUrl; const toInsert = applyFormat( - create( { text: newUrl } ), + create( { text: newText } ), format, 0, - newUrl.length + newText.length ); onChange( insert( value, toInsert ) ); } else { - onChange( applyFormat( value, format ) ); + const newValue = applyFormat( value, format ); + newValue.start = newValue.end; + newValue.activeFormats = []; + onChange( newValue ); } // Focus should only be shifted back to the formatted segment when the diff --git a/packages/format-library/src/link/modal.native.js b/packages/format-library/src/link/modal.native.js index 79072fbd65cc11..d288b69262a591 100644 --- a/packages/format-library/src/link/modal.native.js +++ b/packages/format-library/src/link/modal.native.js @@ -169,6 +169,7 @@ class ModalLinkUI extends Component { autoCorrect={ false } keyboardType="url" onChangeValue={ this.onChangeInputValue } + onSubmit={ this.onDismiss } autoFocus={ Platform.OS === 'ios' } /> /* eslint-enable jsx-a11y/no-autofocus */ @@ -179,6 +180,7 @@ class ModalLinkUI extends Component { value={ text } placeholder={ __( 'Add link text' ) } onChangeValue={ this.onChangeText } + onSubmit={ this.onDismiss } /> <BottomSheet.SwitchCell icon={ external } diff --git a/packages/hooks/package.json b/packages/hooks/package.json index 260515652d5b3d..14a8bbdd18ecf9 100644 --- a/packages/hooks/package.json +++ b/packages/hooks/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/hooks", - "version": "2.7.0", + "version": "2.8.0", "description": "WordPress hooks library.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -21,7 +21,7 @@ "module": "build-module/index.js", "react-native": "src/index", "dependencies": { - "@babel/runtime": "^7.8.3" + "@babel/runtime": "^7.9.2" }, "publishConfig": { "access": "public" diff --git a/packages/html-entities/CHANGELOG.md b/packages/html-entities/CHANGELOG.md index f9355f9f968653..d0c96c0eef6a5f 100644 --- a/packages/html-entities/CHANGELOG.md +++ b/packages/html-entities/CHANGELOG.md @@ -1,3 +1,11 @@ +## Master + +## 2.7.0 (2020-04-15) + +### New feature + +- Include TypeScript type declarations ([#20669](https://github.com/WordPress/gutenberg/pull/20669)) + ## 2.0.2 (2018-12-12) ## 2.0.1 (2018-11-21) diff --git a/packages/html-entities/package.json b/packages/html-entities/package.json index 5e0cb8c0f1d047..cbb5e03d7c1b46 100644 --- a/packages/html-entities/package.json +++ b/packages/html-entities/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/html-entities", - "version": "2.6.0", + "version": "2.7.0", "description": "HTML entity utilities for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -21,8 +21,9 @@ "main": "build/index.js", "module": "build-module/index.js", "react-native": "src/index", + "types": "build-types", "dependencies": { - "@babel/runtime": "^7.8.3" + "@babel/runtime": "^7.9.2" }, "publishConfig": { "access": "public" diff --git a/packages/html-entities/src/index.js b/packages/html-entities/src/index.js index 615087f992e78d..25e440748765cf 100644 --- a/packages/html-entities/src/index.js +++ b/packages/html-entities/src/index.js @@ -1,3 +1,4 @@ +/** @type {HTMLTextAreaElement} */ let _decodeTextArea; /** @@ -36,5 +37,23 @@ export function decodeEntities( html ) { _decodeTextArea.innerHTML = html; const decoded = _decodeTextArea.textContent; _decodeTextArea.innerHTML = ''; - return decoded; + + /** + * Cast to string, HTMLTextAreaElement should always have `string` textContent. + * + * > The `textContent` property of the `Node` interface represents the text content of the + * > node and its descendants. + * > + * > Value: A string or `null` + * > + * > * If the node is a `document` or a Doctype, `textContent` returns `null`. + * > * If the node is a CDATA section, comment, processing instruction, or text node, + * > textContent returns the text inside the node, i.e., the `Node.nodeValue`. + * > * For other node types, `textContent returns the concatenation of the textContent of + * > every child node, excluding comments and processing instructions. (This is an empty + * > string if the node has no children.) + * + * @see https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent + */ + return /** @type {string} */ ( decoded ); } diff --git a/packages/html-entities/tsconfig.json b/packages/html-entities/tsconfig.json new file mode 100644 index 00000000000000..3c2c31f506f132 --- /dev/null +++ b/packages/html-entities/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "src", + "declarationDir": "build-types" + }, + "include": [ "src/**/*" ] +} diff --git a/packages/i18n/CHANGELOG.md b/packages/i18n/CHANGELOG.md index 700b3b520eefbf..bc2101147eda49 100644 --- a/packages/i18n/CHANGELOG.md +++ b/packages/i18n/CHANGELOG.md @@ -1,8 +1,17 @@ ## Master +## 3.11.0 (2020-04-15) + +### New Features + +- Include TypeScript type declarations ([#18942](https://github.com/WordPress/gutenberg/pull/18942)) +- Add `createI18n` method to allow creation of multiple i18n instances ([#21182](https://github.com/WordPress/gutenberg/pull/21182)) + +## 3.10.0 (2020-04-01) + ### New Feature -- Add `isRTL` function (#20298) +- Add `isRTL` function ([#20298](https://github.com/WordPress/gutenberg/pull/20298)) ## 3.1.0 (2018-11-15) diff --git a/packages/i18n/README.md b/packages/i18n/README.md index 21847b5f3f0172..f57ce4124c191b 100644 --- a/packages/i18n/README.md +++ b/packages/i18n/README.md @@ -27,6 +27,19 @@ For a complete example, see the [Internationalization section of the Block Edito <!-- START TOKEN(Autogenerated API docs) --> +<a name="createI18n" href="#createI18n">#</a> **createI18n** + +Create an i18n instance + +_Parameters_ + +- _initialData_ `[LocaleData]`: Locale data configuration. +- _initialDomain_ `[string]`: Domain for which configuration applies. + +_Returns_ + +- `I18n`: I18n instance + <a name="isRTL" href="#isRTL">#</a> **isRTL** Check if current locale is RTL. diff --git a/packages/i18n/package.json b/packages/i18n/package.json index a328ecf0959d09..7c341899f1700e 100644 --- a/packages/i18n/package.json +++ b/packages/i18n/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/i18n", - "version": "3.9.0", + "version": "3.11.0", "description": "WordPress internationalization (i18n) library.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -20,16 +20,17 @@ "main": "build/index.js", "module": "build-module/index.js", "react-native": "src/index", + "types": "build-types", "bin": { "pot-to-php": "./tools/pot-to-php.js" }, "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "gettext-parser": "^1.3.1", "lodash": "^4.17.15", - "memize": "^1.0.5", + "memize": "^1.1.0", "sprintf-js": "^1.1.1", - "tannin": "^1.1.0" + "tannin": "^1.2.0" }, "publishConfig": { "access": "public" diff --git a/packages/i18n/src/create-i18n.js b/packages/i18n/src/create-i18n.js new file mode 100644 index 00000000000000..0b0b4cd1826d14 --- /dev/null +++ b/packages/i18n/src/create-i18n.js @@ -0,0 +1,200 @@ +/** + * External dependencies + */ +import Tannin from 'tannin'; + +/** + * @typedef {Record<string,any>} LocaleData + */ + +/** + * Default locale data to use for Tannin domain when not otherwise provided. + * Assumes an English plural forms expression. + * + * @type {LocaleData} + */ +const DEFAULT_LOCALE_DATA = { + '': { + /** @param {number} n */ + plural_forms( n ) { + return n === 1 ? 0 : 1; + }, + }, +}; + +/** + * An i18n instance + * + * @typedef {Object} I18n + * @property {Function} setLocaleData Merges locale data into the Tannin instance by domain. Accepts data in a + * Jed-formatted JSON object shape. + * @property {Function} __ Retrieve the translation of text. + * @property {Function} _x Retrieve translated string with gettext context. + * @property {Function} _n Translates and retrieves the singular or plural form based on the supplied + * number. + * @property {Function} _nx Translates and retrieves the singular or plural form based on the supplied + * number, with gettext context. + * @property {Function} isRTL Check if current locale is RTL. + */ + +/** + * Create an i18n instance + * + * @param {LocaleData} [initialData] Locale data configuration. + * @param {string} [initialDomain] Domain for which configuration applies. + * @return {I18n} I18n instance + */ +export const createI18n = ( initialData, initialDomain ) => { + /** + * The underlying instance of Tannin to which exported functions interface. + * + * @type {Tannin} + */ + const tannin = new Tannin( {} ); + + /** + * Merges locale data into the Tannin instance by domain. Accepts data in a + * Jed-formatted JSON object shape. + * + * @see http://messageformat.github.io/Jed/ + * + * @param {LocaleData} [data] Locale data configuration. + * @param {string} [domain] Domain for which configuration applies. + */ + const setLocaleData = ( data, domain = 'default' ) => { + tannin.data[ domain ] = { + ...DEFAULT_LOCALE_DATA, + ...tannin.data[ domain ], + ...data, + }; + + // Populate default domain configuration (supported locale date which omits + // a plural forms expression). + tannin.data[ domain ][ '' ] = { + ...DEFAULT_LOCALE_DATA[ '' ], + ...tannin.data[ domain ][ '' ], + }; + }; + + /** + * Wrapper for Tannin's `dcnpgettext`. Populates default locale data if not + * otherwise previously assigned. + * + * @param {string|undefined} domain Domain to retrieve the translated text. + * @param {string|undefined} context Context information for the translators. + * @param {string} single Text to translate if non-plural. Used as + * fallback return value on a caught error. + * @param {string} [plural] The text to be used if the number is + * plural. + * @param {number} [number] The number to compare against to use + * either the singular or plural form. + * + * @return {string} The translated string. + */ + const dcnpgettext = ( + domain = 'default', + context, + single, + plural, + number + ) => { + if ( ! tannin.data[ domain ] ) { + setLocaleData( undefined, domain ); + } + + return tannin.dcnpgettext( domain, context, single, plural, number ); + }; + + /** + * Retrieve the translation of text. + * + * @see https://developer.wordpress.org/reference/functions/__/ + * + * @param {string} text Text to translate. + * @param {string} [domain] Domain to retrieve the translated text. + * + * @return {string} Translated text. + */ + const __ = ( text, domain ) => { + return dcnpgettext( domain, undefined, text ); + }; + + /** + * Retrieve translated string with gettext context. + * + * @see https://developer.wordpress.org/reference/functions/_x/ + * + * @param {string} text Text to translate. + * @param {string} context Context information for the translators. + * @param {string} [domain] Domain to retrieve the translated text. + * + * @return {string} Translated context string without pipe. + */ + const _x = ( text, context, domain ) => { + return dcnpgettext( domain, context, text ); + }; + + /** + * Translates and retrieves the singular or plural form based on the supplied + * number. + * + * @see https://developer.wordpress.org/reference/functions/_n/ + * + * @param {string} single The text to be used if the number is singular. + * @param {string} plural The text to be used if the number is plural. + * @param {number} number The number to compare against to use either the + * singular or plural form. + * @param {string} [domain] Domain to retrieve the translated text. + * + * @return {string} The translated singular or plural form. + */ + const _n = ( single, plural, number, domain ) => { + return dcnpgettext( domain, undefined, single, plural, number ); + }; + + /** + * Translates and retrieves the singular or plural form based on the supplied + * number, with gettext context. + * + * @see https://developer.wordpress.org/reference/functions/_nx/ + * + * @param {string} single The text to be used if the number is singular. + * @param {string} plural The text to be used if the number is plural. + * @param {number} number The number to compare against to use either the + * singular or plural form. + * @param {string} context Context information for the translators. + * @param {string} [domain] Domain to retrieve the translated text. + * + * @return {string} The translated singular or plural form. + */ + const _nx = ( single, plural, number, context, domain ) => { + return dcnpgettext( domain, context, single, plural, number ); + }; + + /** + * Check if current locale is RTL. + * + * **RTL (Right To Left)** is a locale property indicating that text is written from right to left. + * For example, the `he` locale (for Hebrew) specifies right-to-left. Arabic (ar) is another common + * language written RTL. The opposite of RTL, LTR (Left To Right) is used in other languages, + * including English (`en`, `en-US`, `en-GB`, etc.), Spanish (`es`), and French (`fr`). + * + * @return {boolean} Whether locale is RTL. + */ + const isRTL = () => { + return 'rtl' === _x( 'ltr', 'text direction' ); + }; + + if ( initialData ) { + setLocaleData( initialData, initialDomain ); + } + + return { + setLocaleData, + __, + _x, + _n, + _nx, + isRTL, + }; +}; diff --git a/packages/i18n/src/default-i18n.js b/packages/i18n/src/default-i18n.js new file mode 100644 index 00000000000000..c5fdc8c06548be --- /dev/null +++ b/packages/i18n/src/default-i18n.js @@ -0,0 +1,96 @@ +/** + * Internal dependencies + */ +import { createI18n } from './create-i18n'; + +const i18n = createI18n(); + +/* + * Comments in this file are duplicated from ./i18n due to + * https://github.com/WordPress/gutenberg/pull/20318#issuecomment-590837722 + */ + +/** + * @typedef {import('./create-i18n').LocaleData} LocaleData + */ + +/** + * Merges locale data into the Tannin instance by domain. Accepts data in a + * Jed-formatted JSON object shape. + * + * @see http://messageformat.github.io/Jed/ + * + * @param {LocaleData} [data] Locale data configuration. + * @param {string} [domain] Domain for which configuration applies. + */ +export const setLocaleData = i18n.setLocaleData.bind( i18n ); + +/** + * Retrieve the translation of text. + * + * @see https://developer.wordpress.org/reference/functions/__/ + * + * @param {string} text Text to translate. + * @param {string} [domain] Domain to retrieve the translated text. + * + * @return {string} Translated text. + */ +export const __ = i18n.__.bind( i18n ); + +/** + * Retrieve translated string with gettext context. + * + * @see https://developer.wordpress.org/reference/functions/_x/ + * + * @param {string} text Text to translate. + * @param {string} context Context information for the translators. + * @param {string} [domain] Domain to retrieve the translated text. + * + * @return {string} Translated context string without pipe. + */ +export const _x = i18n._x.bind( i18n ); + +/** + * Translates and retrieves the singular or plural form based on the supplied + * number. + * + * @see https://developer.wordpress.org/reference/functions/_n/ + * + * @param {string} single The text to be used if the number is singular. + * @param {string} plural The text to be used if the number is plural. + * @param {number} number The number to compare against to use either the + * singular or plural form. + * @param {string} [domain] Domain to retrieve the translated text. + * + * @return {string} The translated singular or plural form. + */ +export const _n = i18n._n.bind( i18n ); + +/** + * Translates and retrieves the singular or plural form based on the supplied + * number, with gettext context. + * + * @see https://developer.wordpress.org/reference/functions/_nx/ + * + * @param {string} single The text to be used if the number is singular. + * @param {string} plural The text to be used if the number is plural. + * @param {number} number The number to compare against to use either the + * singular or plural form. + * @param {string} context Context information for the translators. + * @param {string} [domain] Domain to retrieve the translated text. + * + * @return {string} The translated singular or plural form. + */ +export const _nx = i18n._nx.bind( i18n ); + +/** + * Check if current locale is RTL. + * + * **RTL (Right To Left)** is a locale property indicating that text is written from right to left. + * For example, the `he` locale (for Hebrew) specifies right-to-left. Arabic (ar) is another common + * language written RTL. The opposite of RTL, LTR (Left To Right) is used in other languages, + * including English (`en`, `en-US`, `en-GB`, etc.), Spanish (`es`), and French (`fr`). + * + * @return {boolean} Whether locale is RTL. + */ +export const isRTL = i18n.isRTL.bind( i18n ); diff --git a/packages/i18n/src/index.js b/packages/i18n/src/index.js index 2b4286819c9cad..e5e04852a3c227 100644 --- a/packages/i18n/src/index.js +++ b/packages/i18n/src/index.js @@ -1,186 +1,3 @@ -/** - * External dependencies - */ -import Tannin from 'tannin'; -import memoize from 'memize'; -import sprintfjs from 'sprintf-js'; - -/** - * @typedef {{[key: string]: any}} LocaleData - */ - -/** - * Default locale data to use for Tannin domain when not otherwise provided. - * Assumes an English plural forms expression. - * - * @type {LocaleData} - */ -const DEFAULT_LOCALE_DATA = { - '': { - plural_forms: ( n ) => ( n === 1 ? 0 : 1 ), - }, -}; - -/** - * Log to console, once per message; or more precisely, per referentially equal - * argument set. Because Jed throws errors, we log these to the console instead - * to avoid crashing the application. - * - * @param {...*} args Arguments to pass to `console.error` - */ -const logErrorOnce = memoize( console.error ); // eslint-disable-line no-console - -/** - * The underlying instance of Tannin to which exported functions interface. - * - * @type {Tannin} - */ -const i18n = new Tannin( {} ); - -/** - * Merges locale data into the Tannin instance by domain. Accepts data in a - * Jed-formatted JSON object shape. - * - * @see http://messageformat.github.io/Jed/ - * - * @param {LocaleData} [data] Locale data configuration. - * @param {string} [domain] Domain for which configuration applies. - */ -export function setLocaleData( data, domain = 'default' ) { - i18n.data[ domain ] = { - ...DEFAULT_LOCALE_DATA, - ...i18n.data[ domain ], - ...data, - }; - - // Populate default domain configuration (supported locale date which omits - // a plural forms expression). - i18n.data[ domain ][ '' ] = { - ...DEFAULT_LOCALE_DATA[ '' ], - ...i18n.data[ domain ][ '' ], - }; -} - -/** - * Wrapper for Tannin's `dcnpgettext`. Populates default locale data if not - * otherwise previously assigned. - * - * @param {string|undefined} domain Domain to retrieve the translated text. - * @param {string|undefined} context Context information for the translators. - * @param {string} single Text to translate if non-plural. Used as - * fallback return value on a caught error. - * @param {string} [plural] The text to be used if the number is - * plural. - * @param {number} [number] The number to compare against to use - * either the singular or plural form. - * - * @return {string} The translated string. - */ -function dcnpgettext( domain = 'default', context, single, plural, number ) { - if ( ! i18n.data[ domain ] ) { - setLocaleData( undefined, domain ); - } - - return i18n.dcnpgettext( domain, context, single, plural, number ); -} - -/** - * Retrieve the translation of text. - * - * @see https://developer.wordpress.org/reference/functions/__/ - * - * @param {string} text Text to translate. - * @param {string} [domain] Domain to retrieve the translated text. - * - * @return {string} Translated text. - */ -export function __( text, domain ) { - return dcnpgettext( domain, undefined, text ); -} - -/** - * Retrieve translated string with gettext context. - * - * @see https://developer.wordpress.org/reference/functions/_x/ - * - * @param {string} text Text to translate. - * @param {string} context Context information for the translators. - * @param {string} [domain] Domain to retrieve the translated text. - * - * @return {string} Translated context string without pipe. - */ -export function _x( text, context, domain ) { - return dcnpgettext( domain, context, text ); -} - -/** - * Translates and retrieves the singular or plural form based on the supplied - * number. - * - * @see https://developer.wordpress.org/reference/functions/_n/ - * - * @param {string} single The text to be used if the number is singular. - * @param {string} plural The text to be used if the number is plural. - * @param {number} number The number to compare against to use either the - * singular or plural form. - * @param {string} [domain] Domain to retrieve the translated text. - * - * @return {string} The translated singular or plural form. - */ -export function _n( single, plural, number, domain ) { - return dcnpgettext( domain, undefined, single, plural, number ); -} - -/** - * Translates and retrieves the singular or plural form based on the supplied - * number, with gettext context. - * - * @see https://developer.wordpress.org/reference/functions/_nx/ - * - * @param {string} single The text to be used if the number is singular. - * @param {string} plural The text to be used if the number is plural. - * @param {number} number The number to compare against to use either the - * singular or plural form. - * @param {string} context Context information for the translators. - * @param {string} [domain] Domain to retrieve the translated text. - * - * @return {string} The translated singular or plural form. - */ -export function _nx( single, plural, number, context, domain ) { - return dcnpgettext( domain, context, single, plural, number ); -} - -/** - * Check if current locale is RTL. - * - * **RTL (Right To Left)** is a locale property indicating that text is written from right to left. - * For example, the `he` locale (for Hebrew) specifies right-to-left. Arabic (ar) is another common - * language written RTL. The opposite of RTL, LTR (Left To Right) is used in other languages, - * including English (`en`, `en-US`, `en-GB`, etc.), Spanish (`es`), and French (`fr`). - * - * @return {boolean} Whether locale is RTL. - */ -export function isRTL() { - return 'rtl' === _x( 'ltr', 'text direction' ); -} - -/** - * Returns a formatted string. If an error occurs in applying the format, the - * original format string is returned. - * - * @param {string} format The format of the string to generate. - * @param {...string} args Arguments to apply to the format. - * - * @see http://www.diveintojavascript.com/projects/javascript-sprintf - * - * @return {string} The formatted string. - */ -export function sprintf( format, ...args ) { - try { - return sprintfjs.sprintf( format, ...args ); - } catch ( error ) { - logErrorOnce( 'sprintf error: \n\n' + error.toString() ); - - return format; - } -} +export { sprintf } from './sprintf'; +export * from './create-i18n'; +export { setLocaleData, __, _x, _n, _nx, isRTL } from './default-i18n'; diff --git a/packages/i18n/src/sprintf.js b/packages/i18n/src/sprintf.js new file mode 100644 index 00000000000000..397fe7abe4e40f --- /dev/null +++ b/packages/i18n/src/sprintf.js @@ -0,0 +1,35 @@ +/** + * External dependencies + */ +import memoize from 'memize'; +import sprintfjs from 'sprintf-js'; + +/** + * Log to console, once per message; or more precisely, per referentially equal + * argument set. Because Jed throws errors, we log these to the console instead + * to avoid crashing the application. + * + * @param {...*} args Arguments to pass to `console.error` + */ +const logErrorOnce = memoize( console.error ); // eslint-disable-line no-console + +/** + * Returns a formatted string. If an error occurs in applying the format, the + * original format string is returned. + * + * @param {string} format The format of the string to generate. + * @param {...string} args Arguments to apply to the format. + * + * @see http://www.diveintojavascript.com/projects/javascript-sprintf + * + * @return {string} The formatted string. + */ +export function sprintf( format, ...args ) { + try { + return sprintfjs.sprintf( format, ...args ); + } catch ( error ) { + logErrorOnce( 'sprintf error: \n\n' + error.toString() ); + + return format; + } +} diff --git a/packages/i18n/src/test/create-i18n.js b/packages/i18n/src/test/create-i18n.js new file mode 100644 index 00000000000000..ef21d468a33721 --- /dev/null +++ b/packages/i18n/src/test/create-i18n.js @@ -0,0 +1,194 @@ +/* eslint-disable @wordpress/i18n-text-domain, @wordpress/i18n-translator-comments */ + +/** + * Internal dependencies + */ +import { createI18n } from '..'; + +const strayaLocale = { + hello: [ 'gday' ], +}; + +const frenchLocale = { + hello: [ 'bonjour' ], +}; + +const localeData = { + '': { + // Domain name + domain: 'test_domain', + lang: 'fr', + // Plural form function for language + plural_forms: 'nplurals=2; plural=(n != 1);', + }, + + hello: [ 'bonjour' ], + + 'verb\u0004feed': [ 'nourrir' ], + + 'hello %s': [ 'bonjour %s' ], + + '%d banana': [ '%d banane', '%d bananes' ], + + 'fruit\u0004%d apple': [ '%d pomme', '%d pommes' ], +}; + +const additionalLocaleData = { + cheeseburger: [ 'hamburger au fromage' ], + '%d cat': [ '%d chat', '%d chats' ], +}; + +const createTestLocale = () => createI18n( localeData, 'test_domain' ); +const createTestLocaleWithAdditionalData = () => { + const locale = createI18n( localeData, 'test_domain' ); + locale.setLocaleData( additionalLocaleData, 'test_domain' ); + return locale; +}; + +describe( 'createI18n', () => { + test( 'instantiated with locale data', () => { + const straya = createI18n( strayaLocale ); + expect( straya.__( 'hello' ) ).toEqual( 'gday' ); + } ); + + test( 'multiple instances maintain their own distinct locale data', () => { + const straya = createI18n(); + const french = createI18n(); + + straya.setLocaleData( strayaLocale ); + french.setLocaleData( frenchLocale ); + + expect( straya.__( 'hello' ) ).toEqual( 'gday' ); + expect( french.__( 'hello' ) ).toEqual( 'bonjour' ); + } ); + + describe( '__', () => { + it( 'use the translation', () => { + const locale = createTestLocale(); + expect( locale.__( 'hello', 'test_domain' ) ).toBe( 'bonjour' ); + } ); + } ); + + describe( '_x', () => { + it( 'use the translation with context', () => { + const locale = createTestLocale(); + expect( locale._x( 'feed', 'verb', 'test_domain' ) ).toBe( + 'nourrir' + ); + } ); + } ); + + describe( '_n', () => { + it( 'use the plural form', () => { + const locale = createTestLocale(); + expect( + locale._n( '%d banana', '%d bananas', 3, 'test_domain' ) + ).toBe( '%d bananes' ); + } ); + + it( 'use the singular form', () => { + const locale = createTestLocale(); + expect( + locale._n( '%d banana', '%d bananas', 1, 'test_domain' ) + ).toBe( '%d banane' ); + } ); + } ); + + describe( '_nx', () => { + it( 'use the plural form', () => { + const locale = createTestLocale(); + expect( + locale._nx( '%d apple', '%d apples', 3, 'fruit', 'test_domain' ) + ).toBe( '%d pommes' ); + } ); + + it( 'use the singular form', () => { + const locale = createTestLocale(); + expect( + locale._nx( '%d apple', '%d apples', 1, 'fruit', 'test_domain' ) + ).toBe( '%d pomme' ); + } ); + } ); + + describe( 'isRTL', () => { + const ARLocaleData = { + '': { + plural_forms: + 'nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;', + language: 'ar', + localeSlug: 'ar', + }, + 'text direction\u0004ltr': [ 'rtl' ], + Back: [ 'رجوع' ], + }; + + it( 'is false for non-rtl', () => { + const locale = createI18n(); + expect( locale.isRTL() ).toBe( false ); + } ); + + it( 'is true for rtl', () => { + const locale = createI18n( ARLocaleData ); + expect( locale.isRTL() ).toBe( true ); + } ); + } ); + + describe( 'setLocaleData', () => { + it( 'supports omitted plural forms expression', () => { + const locale = createTestLocaleWithAdditionalData(); + locale.setLocaleData( + { + '': { + domain: 'test_domain2', + lang: 'fr', + }, + + '%d banana': [ '%d banane', '%d bananes' ], + }, + 'test_domain2' + ); + expect( + locale._n( '%d banana', '%d bananes', 2, 'test_domain2' ) + ).toBe( '%d bananes' ); + } ); + + describe( '__', () => { + it( 'existing translation still available', () => { + const locale = createTestLocaleWithAdditionalData(); + expect( locale.__( 'hello', 'test_domain' ) ).toBe( 'bonjour' ); + } ); + + it( 'new translation available.', () => { + const locale = createTestLocaleWithAdditionalData(); + expect( locale.__( 'cheeseburger', 'test_domain' ) ).toBe( + 'hamburger au fromage' + ); + } ); + } ); + + describe( '_n', () => { + it( 'existing plural form still works', () => { + const locale = createTestLocaleWithAdditionalData(); + expect( + locale._n( '%d banana', '%d bananas', 3, 'test_domain' ) + ).toBe( '%d bananes' ); + } ); + + it( 'new singular form was added', () => { + const locale = createTestLocaleWithAdditionalData(); + expect( + locale._n( '%d cat', '%d cats', 1, 'test_domain' ) + ).toBe( '%d chat' ); + } ); + + it( 'new plural form was added', () => { + const locale = createTestLocaleWithAdditionalData(); + expect( + locale._n( '%d cat', '%d cats', 3, 'test_domain' ) + ).toBe( '%d chats' ); + } ); + } ); + } ); +} ); + +/* eslint-enable @wordpress/i18n-text-domain, @wordpress/i18n-translator-comments */ diff --git a/packages/i18n/src/test/index.js b/packages/i18n/src/test/index.js deleted file mode 100644 index 5246bc8f3659b1..00000000000000 --- a/packages/i18n/src/test/index.js +++ /dev/null @@ -1,187 +0,0 @@ -// Mock memoization as identity function. Inline since Jest errors on out-of- -// scope references in a mock callback. -jest.mock( 'memize', () => ( fn ) => fn ); - -const localeData = { - '': { - // Domain name - domain: 'test_domain', - lang: 'fr', - // Plural form function for language - plural_forms: 'nplurals=2; plural=(n != 1);', - }, - - hello: [ 'bonjour' ], - - 'verb\u0004feed': [ 'nourrir' ], - - 'hello %s': [ 'bonjour %s' ], - - '%d banana': [ '%d banane', '%d bananes' ], - - 'fruit\u0004%d apple': [ '%d pomme', '%d pommes' ], -}; -const additionalLocaleData = { - cheeseburger: [ 'hamburger au fromage' ], - '%d cat': [ '%d chat', '%d chats' ], -}; - -// Get clean locale data -let sprintf, __, _x, _n, _nx, isRTL, setLocaleData; -beforeEach( () => { - const module = require.resolve( '..' ); - delete require.cache[ module ]; - ( { sprintf, __, _x, _n, _nx, isRTL, setLocaleData } = require( '..' ) ); -} ); - -describe( 'i18n', () => { - describe( '__', () => { - beforeEach( setDefaultLocalData ); - - it( 'use the translation', () => { - expect( __( 'hello', 'test_domain' ) ).toBe( 'bonjour' ); - } ); - } ); - - describe( '_x', () => { - beforeEach( setDefaultLocalData ); - - it( 'use the translation with context', () => { - expect( _x( 'feed', 'verb', 'test_domain' ) ).toBe( 'nourrir' ); - } ); - } ); - - describe( '_n', () => { - beforeEach( setDefaultLocalData ); - - it( 'use the plural form', () => { - expect( _n( '%d banana', '%d bananas', 3, 'test_domain' ) ).toBe( - '%d bananes' - ); - } ); - - it( 'use the singular form', () => { - expect( _n( '%d banana', '%d bananas', 1, 'test_domain' ) ).toBe( - '%d banane' - ); - } ); - } ); - - describe( '_nx', () => { - beforeEach( setDefaultLocalData ); - - it( 'use the plural form', () => { - expect( - _nx( '%d apple', '%d apples', 3, 'fruit', 'test_domain' ) - ).toBe( '%d pommes' ); - } ); - - it( 'use the singular form', () => { - expect( - _nx( '%d apple', '%d apples', 1, 'fruit', 'test_domain' ) - ).toBe( '%d pomme' ); - } ); - } ); - - describe( 'isRTL', () => { - const ARLocaleData = { - '': { - plural_forms: - 'nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;', - language: 'ar', - localeSlug: 'ar', - }, - 'text direction\u0004ltr': [ 'rtl' ], - Back: [ 'رجوع' ], - }; - - it( 'is false for non-rtl', () => { - expect( isRTL() ).toBe( false ); - } ); - - it( 'is true for rtl', () => { - setLocaleData( ARLocaleData ); - expect( isRTL() ).toBe( true ); - } ); - } ); - - describe( 'sprintf', () => { - beforeEach( setDefaultLocalData ); - - it( 'absorbs errors', () => { - // Disable reason: Failing case is the purpose of the test. - // eslint-disable-next-line @wordpress/valid-sprintf - const result = sprintf( 'Hello %(placeholder-not-provided)s' ); - - expect( console ).toHaveErrored(); - expect( result ).toBe( 'Hello %(placeholder-not-provided)s' ); - } ); - - it( 'replaces placeholders', () => { - const result = sprintf( __( 'hello %s', 'test_domain' ), 'Riad' ); - - expect( result ).toBe( 'bonjour Riad' ); - } ); - } ); - - describe( 'setLocaleData', () => { - beforeAll( () => { - setDefaultLocalData(); - setLocaleData( additionalLocaleData, 'test_domain' ); - } ); - - it( 'supports omitted plural forms expression', () => { - setLocaleData( - { - '': { - domain: 'test_domain2', - lang: 'fr', - }, - - '%d banana': [ '%d banane', '%d bananes' ], - }, - 'test_domain2' - ); - - expect( _n( '%d banana', '%d bananes', 2, 'test_domain2' ) ).toBe( - '%d bananes' - ); - } ); - - describe( '__', () => { - it( 'existing translation still available', () => { - expect( __( 'hello', 'test_domain' ) ).toBe( 'bonjour' ); - } ); - - it( 'new translation available.', () => { - expect( __( 'cheeseburger', 'test_domain' ) ).toBe( - 'hamburger au fromage' - ); - } ); - } ); - - describe( '_n', () => { - it( 'existing plural form still works', () => { - expect( - _n( '%d banana', '%d bananas', 3, 'test_domain' ) - ).toBe( '%d bananes' ); - } ); - - it( 'new singular form was added', () => { - expect( _n( '%d cat', '%d cats', 1, 'test_domain' ) ).toBe( - '%d chat' - ); - } ); - - it( 'new plural form was added', () => { - expect( _n( '%d cat', '%d cats', 3, 'test_domain' ) ).toBe( - '%d chats' - ); - } ); - } ); - } ); -} ); - -function setDefaultLocalData() { - setLocaleData( localeData, 'test_domain' ); -} diff --git a/packages/i18n/src/test/sprintf.js b/packages/i18n/src/test/sprintf.js new file mode 100644 index 00000000000000..035d3b3a4b3d41 --- /dev/null +++ b/packages/i18n/src/test/sprintf.js @@ -0,0 +1,27 @@ +// Mock memoization as identity function. Inline since Jest errors on +// out-of-scope references in a mock callback. +jest.mock( 'memize', () => ( fn ) => fn ); + +/** + * Internal dependencies + */ +import { sprintf } from '../sprintf'; + +describe( 'i18n', () => { + describe( 'sprintf', () => { + it( 'absorbs errors', () => { + // Disable reason: Failing case is the purpose of the test. + // eslint-disable-next-line @wordpress/valid-sprintf + const result = sprintf( 'Hello %(placeholder-not-provided)s' ); + + expect( console ).toHaveErrored(); + expect( result ).toBe( 'Hello %(placeholder-not-provided)s' ); + } ); + + it( 'replaces placeholders', () => { + const result = sprintf( 'bonjour %s', 'Riad' ); + + expect( result ).toBe( 'bonjour Riad' ); + } ); + } ); +} ); diff --git a/packages/i18n/tsconfig.json b/packages/i18n/tsconfig.json new file mode 100644 index 00000000000000..3c2c31f506f132 --- /dev/null +++ b/packages/i18n/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "src", + "declarationDir": "build-types" + }, + "include": [ "src/**/*" ] +} diff --git a/packages/icons/CHANGELOG.md b/packages/icons/CHANGELOG.md index 15517d8f1ce7c7..ef1afdc9561f8d 100644 --- a/packages/icons/CHANGELOG.md +++ b/packages/icons/CHANGELOG.md @@ -1,5 +1,16 @@ ## Master +## 1.3.1 (2020-04-15) + +### Bug Fix + +- Hide TypeScript type declarations ([#21613](https://github.com/WordPress/gutenberg/pull/21613)) + after they were found to conflict with DefinitelyTyped provided declarations. + +## 1.3.0 (2020-04-15) + +- Include TypeScript type declarations ([#21487](https://github.com/WordPress/gutenberg/pull/21487)) + ## 1.0.0 (2020-02-04) Initial release. diff --git a/packages/icons/_tsconfig.json b/packages/icons/_tsconfig.json new file mode 100644 index 00000000000000..a40438556d26fb --- /dev/null +++ b/packages/icons/_tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "src", + "declarationDir": "build-types" + }, + "include": [ "src/**/*" ], + "references": [ { "path": "../primitives" } ] +} diff --git a/packages/icons/package.json b/packages/icons/package.json index bd246a1cc3da03..dd1f25f846c424 100644 --- a/packages/icons/package.json +++ b/packages/icons/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/icons", - "version": "1.1.0", + "version": "1.3.1", "description": "WordPress Icons package, based on dashicon.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -23,7 +23,7 @@ "module": "build-module/index.js", "react-native": "src/index", "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/element": "../element", "@wordpress/primitives": "../primitives" }, diff --git a/packages/icons/src/icon/index.js b/packages/icons/src/icon/index.js index eb196b9d05b6dc..d80acbd952c30a 100644 --- a/packages/icons/src/icon/index.js +++ b/packages/icons/src/icon/index.js @@ -3,6 +3,20 @@ */ import { cloneElement } from '@wordpress/element'; +// Disable reason: JSDoc linter doesn't seem to parse the union (`&`) correctly. +/* eslint-disable jsdoc/valid-types */ +/** @typedef {{icon: JSX.Element, size?: number} & import('react').ComponentPropsWithoutRef<'SVG'>} IconProps */ +/* eslint-enable jsdoc/valid-types */ + +/** + * Return an SVG icon. + * + * @param {IconProps} props icon is the SVG component to render + * size is a number specifiying the icon size in pixels + * Other props will be passed to wrapped SVG component + * + * @return {JSX.Element} Icon component + */ function Icon( { icon, size = 24, ...props } ) { return cloneElement( icon, { width: size, diff --git a/packages/icons/src/icon/stories/index.js b/packages/icons/src/icon/stories/index.js index ff184207af8568..9d1b2d427809c8 100644 --- a/packages/icons/src/icon/stories/index.js +++ b/packages/icons/src/icon/stories/index.js @@ -42,7 +42,7 @@ export const _default = () => { const LibraryExample = () => { const [ filter, setFilter ] = useState( '' ); - const filteredIcons = omitBy( availableIcons, ( icon, name ) => { + const filteredIcons = omitBy( availableIcons, ( _icon, name ) => { return name.indexOf( filter ) === -1; } ); return ( diff --git a/packages/icons/src/index.js b/packages/icons/src/index.js index c57f714ef3860e..9126efadfb0b56 100644 --- a/packages/icons/src/index.js +++ b/packages/icons/src/index.js @@ -38,6 +38,11 @@ export { default as columns } from './library/columns'; export { default as comment } from './library/comment'; export { default as controlsRepeat } from './library/controls-repeat'; export { default as cover } from './library/cover'; +export { default as create } from './library/create'; +export { default as currencyDollar } from './library/currency-dollar'; +export { default as currencyEuro } from './library/currency-euro'; +export { default as currencyPound } from './library/currency-pound'; +export { default as desktop } from './library/desktop'; export { default as external } from './library/external'; export { default as file } from './library/file'; export { default as formatBold } from './library/format-bold'; @@ -50,10 +55,13 @@ export { default as formatOutdent } from './library/format-outdent'; export { default as formatRtl } from './library/format-rtl'; export { default as formatStrikethrough } from './library/format-strikethrough'; export { default as gallery } from './library/gallery'; +export { default as globe } from './library/globe'; export { default as grid } from './library/grid'; export { default as group } from './library/group'; export { default as heading } from './library/heading'; export { default as help } from './library/help'; +export { default as inbox } from './library/inbox'; +export { default as institution } from './library/institution'; export { default as html } from './library/html'; export { default as image } from './library/image'; export { default as info } from './library/info'; @@ -70,6 +78,7 @@ export { default as media } from './library/media'; export { default as mediaAndText } from './library/media-and-text'; export { default as menu } from './library/menu'; export { default as minus } from './library/minus'; +export { default as mobile } from './library/mobile'; export { default as more } from './library/more'; export { default as moreHorizontal } from './library/more-horizontal'; export { default as moreVertical } from './library/more-vertical'; @@ -77,6 +86,8 @@ export { default as navigation } from './library/navigation'; export { default as pageBreak } from './library/page-break'; export { default as page } from './library/page'; export { default as paragraph } from './library/paragraph'; +export { default as payment } from './library/payment'; +export { default as percent } from './library/percent'; export { default as positionCenter } from './library/position-center'; export { default as positionLeft } from './library/position-left'; export { default as positionRight } from './library/position-right'; @@ -88,22 +99,26 @@ export { default as plusCircle } from './library/plus-circle'; export { default as plus } from './library/plus'; export { default as postList } from './library/post-list'; export { default as preformatted } from './library/preformatted'; +export { default as box } from './library/box'; export { default as pullLeft } from './library/pull-left'; export { default as pullRight } from './library/pull-right'; export { default as pullquote } from './library/pullquote'; export { default as quote } from './library/quote'; +export { default as receipt } from './library/receipt'; export { default as redo } from './library/redo'; export { default as replace } from './library/replace'; export { default as resizeCornerNE } from './library/resize-corner-n-e'; export { default as rss } from './library/rss'; export { default as search } from './library/search'; export { default as separator } from './library/separator'; +export { default as share } from './library/share'; export { default as shortcode } from './library/shortcode'; -export { default as globe } from './library/globe'; +export { default as star } from './library/star'; export { default as starEmpty } from './library/star-empty'; export { default as starFilled } from './library/star-filled'; export { default as starHalf } from './library/star-half'; export { default as stretchFullWidth } from './library/stretch-full-width'; +export { default as shipping } from './library/shipping'; export { default as stretchWide } from './library/stretch-wide'; export { default as tableColumnAfter } from './library/table-column-after'; export { default as tableColumnBefore } from './library/table-column-before'; @@ -114,8 +129,10 @@ export { default as tableRowDelete } from './library/table-row-delete'; export { default as table } from './library/table'; export { default as tag } from './library/tag'; export { default as textColor } from './library/text-color'; +export { default as tablet } from './library/tablet'; export { default as title } from './library/title'; export { default as trash } from './library/trash'; +export { default as typography } from './library/typography'; export { default as undo } from './library/undo'; export { default as update } from './library/update'; export { default as upload } from './library/upload'; diff --git a/packages/icons/src/library/box.js b/packages/icons/src/library/box.js new file mode 100644 index 00000000000000..c2908c5a8adb38 --- /dev/null +++ b/packages/icons/src/library/box.js @@ -0,0 +1,16 @@ +/** + * WordPress dependencies + */ +import { Path, SVG } from '@wordpress/primitives'; + +const box = ( + <SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <Path + fill-rule="evenodd" + d="M5 5.5h14a.5.5 0 01.5.5v1.5a.5.5 0 01-.5.5H5a.5.5 0 01-.5-.5V6a.5.5 0 01.5-.5zM4 9.232A2 2 0 013 7.5V6a2 2 0 012-2h14a2 2 0 012 2v1.5a2 2 0 01-1 1.732V18a2 2 0 01-2 2H6a2 2 0 01-2-2V9.232zm1.5.268V18a.5.5 0 00.5.5h12a.5.5 0 00.5-.5V9.5h-13z" + clip-rule="evenodd" + /> + </SVG> +); + +export default box; diff --git a/packages/icons/src/library/button.js b/packages/icons/src/library/button.js index 4bbe3dd8a6bc78..0e9071bc29fb48 100644 --- a/packages/icons/src/library/button.js +++ b/packages/icons/src/library/button.js @@ -5,7 +5,7 @@ import { Path, SVG } from '@wordpress/primitives'; const button = ( <SVG viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> - <Path d="M19 7H5c-1.1 0-2 .9-2 2v7c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V9c0-1.1-.9-2-2-2zm.5 9c0 .3-.2.5-.5.5H5c-.3 0-.5-.2-.5-.5V9c0-.3.2-.5.5-.5h14c.3 0 .5.2.5.5v7zM8 13.5h8V12H8v1.5z" /> + <Path d="M19 6.5H5c-1.1 0-2 .9-2 2v7c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2v-7c0-1.1-.9-2-2-2zm.5 9c0 .3-.2.5-.5.5H5c-.3 0-.5-.2-.5-.5v-7c0-.3.2-.5.5-.5h14c.3 0 .5.2.5.5v7zM8 13h8v-1.5H8V13z" /> </SVG> ); diff --git a/packages/icons/src/library/create.js b/packages/icons/src/library/create.js new file mode 100644 index 00000000000000..09019e6ef8d924 --- /dev/null +++ b/packages/icons/src/library/create.js @@ -0,0 +1,12 @@ +/** + * WordPress dependencies + */ +import { SVG, Path } from '@wordpress/primitives'; + +const create = ( + <SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <Path d="M16 11.2h-3.2V8h-1.6v3.2H8v1.6h3.2V16h1.6v-3.2H16z" /> + </SVG> +); + +export default create; diff --git a/packages/icons/src/library/currency-dollar.js b/packages/icons/src/library/currency-dollar.js new file mode 100644 index 00000000000000..a93d2037346390 --- /dev/null +++ b/packages/icons/src/library/currency-dollar.js @@ -0,0 +1,12 @@ +/** + * WordPress dependencies + */ +import { Path, SVG } from '@wordpress/primitives'; + +const currencyDollar = ( + <SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <Path d="M3.25 12a8.75 8.75 0 1117.5 0 8.75 8.75 0 01-17.5 0zM12 4.75a7.25 7.25 0 100 14.5 7.25 7.25 0 000-14.5zm-1.338 4.877c-.314.22-.412.452-.412.623 0 .171.098.403.412.623.312.218.783.377 1.338.377.825 0 1.605.233 2.198.648.59.414 1.052 1.057 1.052 1.852 0 .795-.461 1.438-1.052 1.852-.41.286-.907.486-1.448.582v.316a.75.75 0 01-1.5 0v-.316a3.64 3.64 0 01-1.448-.582c-.59-.414-1.052-1.057-1.052-1.852a.75.75 0 011.5 0c0 .171.098.403.412.623.312.218.783.377 1.338.377s1.026-.159 1.338-.377c.314-.22.412-.452.412-.623 0-.171-.098-.403-.412-.623-.312-.218-.783-.377-1.338-.377-.825 0-1.605-.233-2.198-.648-.59-.414-1.052-1.057-1.052-1.852 0-.795.461-1.438 1.052-1.852a3.64 3.64 0 011.448-.582V7.5a.75.75 0 011.5 0v.316c.54.096 1.039.296 1.448.582.59.414 1.052 1.057 1.052 1.852a.75.75 0 01-1.5 0c0-.171-.098-.403-.412-.623-.312-.218-.783-.377-1.338-.377s-1.026.159-1.338.377z" /> + </SVG> +); + +export default currencyDollar; diff --git a/packages/icons/src/library/currency-euro.js b/packages/icons/src/library/currency-euro.js new file mode 100644 index 00000000000000..9522211027175e --- /dev/null +++ b/packages/icons/src/library/currency-euro.js @@ -0,0 +1,12 @@ +/** + * WordPress dependencies + */ +import { Path, SVG } from '@wordpress/primitives'; + +const currencyEuro = ( + <SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <Path d="M12 3.25a8.75 8.75 0 100 17.5 8.75 8.75 0 000-17.5zM4.75 12a7.25 7.25 0 1114.5 0 7.25 7.25 0 01-14.5 0zm9.195 1.944a2.75 2.75 0 01-4.066-.194h.621a.75.75 0 000-1.5H9.262a2.767 2.767 0 010-.5H11.5a.75.75 0 000-1.5H9.88a2.75 2.75 0 014.066-.194.75.75 0 001.06-1.061 4.25 4.25 0 00-6.88 1.255H7.5a.75.75 0 000 1.5h.258c-.01.166-.01.334 0 .5H7.5a.75.75 0 000 1.5h.626a4.25 4.25 0 006.88 1.255.75.75 0 00-1.06-1.06z" /> + </SVG> +); + +export default currencyEuro; diff --git a/packages/icons/src/library/currency-pound.js b/packages/icons/src/library/currency-pound.js new file mode 100644 index 00000000000000..d2ab8494f3c5b3 --- /dev/null +++ b/packages/icons/src/library/currency-pound.js @@ -0,0 +1,15 @@ +/** + * WordPress dependencies + */ +import { Path, SVG } from '@wordpress/primitives'; + +const currencyPound = ( + <SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <Path + fill-rule="evenodd" + d="M3.25 12a8.75 8.75 0 1117.5 0 8.75 8.75 0 01-17.5 0zM12 4.75a7.25 7.25 0 100 14.5 7.25 7.25 0 000-14.5zm.25 4c-.787 0-1.425.638-1.425 1.425 0 .058.014.147.069.3.04.113.088.223.147.36a26.094 26.094 0 01.173.415H12.5a.75.75 0 010 1.5h-.953c.002.047.003.095.003.144 0 .617-.236 1.168-.511 1.606h3.386a.75.75 0 010 1.5H9.35a.75.75 0 01-.452-1.349l.007-.005a4.417 4.417 0 00.596-.581c.328-.39.549-.806.549-1.171 0-.05-.002-.097-.004-.144H9.5a.75.75 0 010-1.5h.088a5.875 5.875 0 01-.106-.27 2.382 2.382 0 01-.157-.805 2.925 2.925 0 015.637-1.097.75.75 0 01-1.39.563 1.426 1.426 0 00-1.322-.891zm-3.35 5.9l.45.6-.45-.6z" + /> + </SVG> +); + +export default currencyPound; diff --git a/packages/icons/src/library/desktop.js b/packages/icons/src/library/desktop.js new file mode 100644 index 00000000000000..f7423731a0bc0c --- /dev/null +++ b/packages/icons/src/library/desktop.js @@ -0,0 +1,12 @@ +/** + * WordPress dependencies + */ +import { SVG, Path } from '@wordpress/primitives'; + +const desktop = ( + <SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <Path d="M20.5 16h-.7V8c0-1.1-.9-2-2-2H6.2c-1.1 0-2 .9-2 2v8h-.7c-.8 0-1.5.7-1.5 1.5h20c0-.8-.7-1.5-1.5-1.5zM5.7 8c0-.3.2-.5.5-.5h11.6c.3 0 .5.2.5.5v7.6H5.7V8z" /> + </SVG> +); + +export default desktop; diff --git a/packages/icons/src/library/html.js b/packages/icons/src/library/html.js index 12373851d46f26..5f1966166d9f28 100644 --- a/packages/icons/src/library/html.js +++ b/packages/icons/src/library/html.js @@ -5,7 +5,7 @@ import { SVG, Path } from '@wordpress/primitives'; const html = ( <SVG viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> - <Path d="M4.5,11h-2V9H1v6h1.5v-2.5h2V15H6V9H4.5V11z M7,10.5h1.5V15H10v-4.5h1.5V9H7V10.5z M14.5,10l-1-1H12v6h1.5v-3.9 l1,1l1-1V15H17V9h-1.5L14.5,10z M19.5,13.5V9H18v6h5v-1.5H19.5z" /> + <Path d="M4.8 11.4H2.1V9H1v6h1.1v-2.6h2.7V15h1.1V9H4.8v2.4zm1.9-1.3h1.7V15h1.1v-4.9h1.7V9H6.7v1.1zM16.2 9l-1.5 2.7L13.3 9h-.9l-.8 6h1.1l.5-4 1.5 2.8 1.5-2.8.5 4h1.1L17 9h-.8zm3.8 5V9h-1.1v6h3.6v-1H20z" /> </SVG> ); diff --git a/packages/icons/src/library/inbox.js b/packages/icons/src/library/inbox.js new file mode 100644 index 00000000000000..41b3cf33448cff --- /dev/null +++ b/packages/icons/src/library/inbox.js @@ -0,0 +1,16 @@ +/** + * WordPress dependencies + */ +import { Path, SVG } from '@wordpress/primitives'; + +const inbox = ( + <SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <Path + fill-rule="evenodd" + d="M6 5.5h12a.5.5 0 01.5.5v7H14a2 2 0 11-4 0H5.5V6a.5.5 0 01.5-.5zm-.5 9V18a.5.5 0 00.5.5h12a.5.5 0 00.5-.5v-3.5h-3.337a3.5 3.5 0 01-6.326 0H5.5zM4 13V6a2 2 0 012-2h12a2 2 0 012 2v12a2 2 0 01-2 2H6a2 2 0 01-2-2v-5z" + clip-rule="evenodd" + /> + </SVG> +); + +export default inbox; diff --git a/packages/icons/src/library/info.js b/packages/icons/src/library/info.js index 7499b180738b3b..f3425d9e950415 100644 --- a/packages/icons/src/library/info.js +++ b/packages/icons/src/library/info.js @@ -5,7 +5,7 @@ import { SVG, Path } from '@wordpress/primitives'; const info = ( <SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> - <Path d="M12 3.2c-4.8 0-8.8 3.9-8.8 8.8 0 4.8 3.9 8.8 8.8 8.8 4.8 0 8.8-3.9 8.8-8.8 0-4.8-4-8.8-8.8-8.8zm0 16c-4 0-7.2-3.3-7.2-7.2C4.8 8 8 4.8 12 4.8s7.2 3.3 7.2 7.2c0 4-3.2 7.2-7.2 7.2zM11 17h2v-5h-2v5zm0-7h2V8h-2v2z" /> + <Path d="M12 3.2c-4.8 0-8.8 3.9-8.8 8.8 0 4.8 3.9 8.8 8.8 8.8 4.8 0 8.8-3.9 8.8-8.8 0-4.8-4-8.8-8.8-8.8zm0 16c-4 0-7.2-3.3-7.2-7.2C4.8 8 8 4.8 12 4.8s7.2 3.3 7.2 7.2c0 4-3.2 7.2-7.2 7.2zM11 17h2v-6h-2v6zm0-8h2V7h-2v2z" /> </SVG> ); diff --git a/packages/icons/src/library/institution.js b/packages/icons/src/library/institution.js new file mode 100644 index 00000000000000..76cb54b6f188a9 --- /dev/null +++ b/packages/icons/src/library/institution.js @@ -0,0 +1,16 @@ +/** + * WordPress dependencies + */ +import { Path, SVG } from '@wordpress/primitives'; + +const institute = ( + <SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <Path + fill-rule="evenodd" + d="M18.646 9H20V8l-1-.5L12 4 5 7.5 4 8v1h14.646zm-3-1.5L12 5.677 8.354 7.5h7.292zm-7.897 9.44v-6.5h-1.5v6.5h1.5zm5-6.5v6.5h-1.5v-6.5h1.5zm5 0v6.5h-1.5v-6.5h1.5zm2.252 8.81c0 .414-.334.75-.748.75H4.752a.75.75 0 010-1.5h14.5a.75.75 0 01.749.75z" + clip-rule="evenodd" + /> + </SVG> +); + +export default institute; diff --git a/packages/icons/src/library/mobile.js b/packages/icons/src/library/mobile.js new file mode 100644 index 00000000000000..4f1f4055337343 --- /dev/null +++ b/packages/icons/src/library/mobile.js @@ -0,0 +1,12 @@ +/** + * WordPress dependencies + */ +import { SVG, Path } from '@wordpress/primitives'; + +const desktop = ( + <SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <Path d="M15 4H9c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h6c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm.5 14c0 .3-.2.5-.5.5H9c-.3 0-.5-.2-.5-.5V6c0-.3.2-.5.5-.5h6c.3 0 .5.2.5.5v12zm-4.5-.5h2V16h-2v1.5z" /> + </SVG> +); + +export default desktop; diff --git a/packages/icons/src/library/page.js b/packages/icons/src/library/page.js index 65a2d571293abc..9f5338f46aea2b 100644 --- a/packages/icons/src/library/page.js +++ b/packages/icons/src/library/page.js @@ -4,8 +4,8 @@ import { SVG, Path } from '@wordpress/primitives'; const page = ( - <SVG xmlns="http://www.w3.org/2000/svg" viewBox="-2 -2 24 24"> - <Path d="M6 15V2h10v13H6zm-1 1h8v2H3V5h2v11z" /> + <SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <Path d="M7 5.5h10a.5.5 0 01.5.5v12a.5.5 0 01-.5.5H7a.5.5 0 01-.5-.5V6a.5.5 0 01.5-.5zM17 4H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V6a2 2 0 00-2-2zm-1 3.75H8v1.5h8v-1.5zM8 11h8v1.5H8V11zm6 3.25H8v1.5h6v-1.5z" /> </SVG> ); diff --git a/packages/icons/src/library/payment.js b/packages/icons/src/library/payment.js new file mode 100644 index 00000000000000..771668ccd0035c --- /dev/null +++ b/packages/icons/src/library/payment.js @@ -0,0 +1,16 @@ +/** + * WordPress dependencies + */ +import { Path, SVG } from '@wordpress/primitives'; + +const payment = ( + <SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <Path + fill-rule="evenodd" + d="M5.5 9.5v-2h13v2h-13zm0 3v4h13v-4h-13zM4 7a1 1 0 011-1h14a1 1 0 011 1v10a1 1 0 01-1 1H5a1 1 0 01-1-1V7z" + clip-rule="evenodd" + /> + </SVG> +); + +export default payment; diff --git a/packages/icons/src/library/percent.js b/packages/icons/src/library/percent.js new file mode 100644 index 00000000000000..663eb4e10b1855 --- /dev/null +++ b/packages/icons/src/library/percent.js @@ -0,0 +1,16 @@ +/** + * WordPress dependencies + */ +import { Path, SVG } from '@wordpress/primitives'; + +const percent = ( + <SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <Path + fill-rule="evenodd" + d="M6.5 8a1.5 1.5 0 103 0 1.5 1.5 0 00-3 0zM8 5a3 3 0 100 6 3 3 0 000-6zm6.5 11a1.5 1.5 0 103 0 1.5 1.5 0 00-3 0zm1.5-3a3 3 0 100 6 3 3 0 000-6zM5.47 17.41a.75.75 0 001.06 1.06L18.47 6.53a.75.75 0 10-1.06-1.06L5.47 17.41z" + clip-rule="evenodd" + /> + </SVG> +); + +export default percent; diff --git a/packages/icons/src/library/post-list.js b/packages/icons/src/library/post-list.js index 0c5fbdfa0c7e84..7656d492d17fd0 100644 --- a/packages/icons/src/library/post-list.js +++ b/packages/icons/src/library/post-list.js @@ -1,17 +1,11 @@ /** * WordPress dependencies */ -import { Path, Rect, SVG } from '@wordpress/primitives'; +import { Path, SVG } from '@wordpress/primitives'; const postList = ( <SVG viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> - <Rect x="11" y="7" width="6" height="2" /> - <Rect x="11" y="11" width="6" height="2" /> - <Rect x="11" y="15" width="6" height="2" /> - <Rect x="7" y="7" width="2" height="2" /> - <Rect x="7" y="11" width="2" height="2" /> - <Rect x="7" y="15" width="2" height="2" /> - <Path d="M20.1,3H3.9C3.4,3,3,3.4,3,3.9v16.2C3,20.5,3.4,21,3.9,21h16.2c0.4,0,0.9-0.5,0.9-0.9V3.9C21,3.4,20.5,3,20.1,3z M19,19H5V5h14V19z" /> + <Path d="M18 4H6c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm.5 14c0 .3-.2.5-.5.5H6c-.3 0-.5-.2-.5-.5V6c0-.3.2-.5.5-.5h12c.3 0 .5.2.5.5v12zM7 11h2V9H7v2zm0 4h2v-2H7v2zm3-4h7V9h-7v2zm0 4h7v-2h-7v2z" /> </SVG> ); diff --git a/packages/icons/src/library/receipt.js b/packages/icons/src/library/receipt.js new file mode 100644 index 00000000000000..7db4280a882ef4 --- /dev/null +++ b/packages/icons/src/library/receipt.js @@ -0,0 +1,16 @@ +/** + * WordPress dependencies + */ +import { Path, SVG } from '@wordpress/primitives'; + +const receipt = ( + <SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <Path + fill-rule="evenodd" + d="M16.83 6.342l.602.3.625-.25.443-.176v12.569l-.443-.178-.625-.25-.603.301-1.444.723-2.41-.804-.475-.158-.474.158-2.41.803-1.445-.722-.603-.3-.625.25-.443.177V6.215l.443.178.625.25.603-.301 1.444-.722 2.41.803.475.158.474-.158 2.41-.803 1.445.722zM20 4l-1.5.6-1 .4-2-1-3 1-3-1-2 1-1-.4L5 4v17l1.5-.6 1-.4 2 1 3-1 3 1 2-1 1 .4 1.5.6V4zm-3.5 6.25v-1.5h-8v1.5h8zm0 3v-1.5h-8v1.5h8zm-8 3v-1.5h8v1.5h-8z" + clip-rule="evenodd" + /> + </SVG> +); + +export default receipt; diff --git a/packages/icons/src/library/search.js b/packages/icons/src/library/search.js index 6ca14df2b2a7d7..a28abf5fce1706 100644 --- a/packages/icons/src/library/search.js +++ b/packages/icons/src/library/search.js @@ -4,8 +4,8 @@ import { SVG, Path } from '@wordpress/primitives'; const search = ( - <SVG xmlns="http://www.w3.org/2000/svg" viewBox="-2 -2 24 24"> - <Path d="M12.14 4.18c1.87 1.87 2.11 4.75.72 6.89.12.1.22.21.36.31.2.16.47.36.81.59.34.24.56.39.66.47.42.31.73.57.94.78.32.32.6.65.84 1 .25.35.44.69.59 1.04.14.35.21.68.18 1-.02.32-.14.59-.36.81s-.49.34-.81.36c-.31.02-.65-.04-.99-.19-.35-.14-.7-.34-1.04-.59-.35-.24-.68-.52-1-.84-.21-.21-.47-.52-.77-.93-.1-.13-.25-.35-.47-.66-.22-.32-.4-.57-.56-.78-.16-.2-.29-.35-.44-.5-2.07 1.09-4.69.76-6.44-.98-2.14-2.15-2.14-5.64 0-7.78 2.15-2.15 5.63-2.15 7.78 0zm-1.41 6.36c1.36-1.37 1.36-3.58 0-4.95-1.37-1.37-3.59-1.37-4.95 0-1.37 1.37-1.37 3.58 0 4.95 1.36 1.37 3.58 1.37 4.95 0z" /> + <SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <Path d="M13.5 6C10.5 6 8 8.5 8 11.5c0 1.1.3 2.1.9 3l-3.4 3 1 1.1 3.4-2.9c1 .9 2.2 1.4 3.6 1.4 3 0 5.5-2.5 5.5-5.5C19 8.5 16.5 6 13.5 6zm0 9.5c-2.2 0-4-1.8-4-4s1.8-4 4-4 4 1.8 4 4-1.8 4-4 4z" /> </SVG> ); diff --git a/packages/icons/src/library/share.js b/packages/icons/src/library/share.js new file mode 100644 index 00000000000000..72e186b99d8b31 --- /dev/null +++ b/packages/icons/src/library/share.js @@ -0,0 +1,12 @@ +/** + * WordPress dependencies + */ +import { Path, SVG } from '@wordpress/primitives'; + +const share = ( + <SVG viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> + <Path d="M9 11.8l6.1-4.5c.1.4.4.7.9.7h2c.6 0 1-.4 1-1V5c0-.6-.4-1-1-1h-2c-.6 0-1 .4-1 1v.4l-6.4 4.8c-.2-.1-.4-.2-.6-.2H6c-.6 0-1 .4-1 1v2c0 .6.4 1 1 1h2c.2 0 .4-.1.6-.2l6.4 4.8v.4c0 .6.4 1 1 1h2c.6 0 1-.4 1-1v-2c0-.6-.4-1-1-1h-2c-.5 0-.8.3-.9.7L9 12.2v-.4z" /> + </SVG> +); + +export default share; diff --git a/packages/icons/src/library/shipping.js b/packages/icons/src/library/shipping.js new file mode 100644 index 00000000000000..71c6c364aa4b3c --- /dev/null +++ b/packages/icons/src/library/shipping.js @@ -0,0 +1,12 @@ +/** + * WordPress dependencies + */ +import { Path, SVG } from '@wordpress/primitives'; + +const shipping = ( + <SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <Path d="M3 6.75C3 5.784 3.784 5 4.75 5H15V7.313l.05.027 5.056 2.73.394.212v3.468a1.75 1.75 0 01-1.75 1.75h-.012a2.5 2.5 0 11-4.975 0H9.737a2.5 2.5 0 11-4.975 0H3V6.75zM13.5 14V6.5H4.75a.25.25 0 00-.25.25V14h.965a2.493 2.493 0 011.785-.75c.7 0 1.332.287 1.785.75H13.5zm4.535 0h.715a.25.25 0 00.25-.25v-2.573l-4-2.16v4.568a2.487 2.487 0 011.25-.335c.7 0 1.332.287 1.785.75zM6.282 15.5a1.002 1.002 0 00.968 1.25 1 1 0 10-.968-1.25zm9 0a1 1 0 101.937.498 1 1 0 00-1.938-.498z" /> + </SVG> +); + +export default shipping; diff --git a/packages/icons/src/library/star.js b/packages/icons/src/library/star.js new file mode 100644 index 00000000000000..ad5546e5dcfe2b --- /dev/null +++ b/packages/icons/src/library/star.js @@ -0,0 +1,12 @@ +/** + * WordPress dependencies + */ +import { Path, SVG } from '@wordpress/primitives'; + +const star = ( + <SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <Path d="M11.776 4.454a.25.25 0 01.448 0l2.069 4.192a.25.25 0 00.188.137l4.626.672a.25.25 0 01.139.426l-3.348 3.263a.25.25 0 00-.072.222l.79 4.607a.25.25 0 01-.362.263l-4.138-2.175a.25.25 0 00-.232 0l-4.138 2.175a.25.25 0 01-.363-.263l.79-4.607a.25.25 0 00-.071-.222L4.754 9.881a.25.25 0 01.139-.426l4.626-.672a.25.25 0 00.188-.137l2.069-4.192z" /> + </SVG> +); + +export default star; diff --git a/packages/icons/src/library/tablet.js b/packages/icons/src/library/tablet.js new file mode 100644 index 00000000000000..791e14dd4798f6 --- /dev/null +++ b/packages/icons/src/library/tablet.js @@ -0,0 +1,12 @@ +/** + * WordPress dependencies + */ +import { SVG, Path } from '@wordpress/primitives'; + +const tablet = ( + <SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <Path d="M17 4H7c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm.5 14c0 .3-.2.5-.5.5H7c-.3 0-.5-.2-.5-.5V6c0-.3.2-.5.5-.5h10c.3 0 .5.2.5.5v12zm-7.5-.5h4V16h-4v1.5z" /> + </SVG> +); + +export default tablet; diff --git a/packages/icons/src/library/trending-down.js b/packages/icons/src/library/trending-down.js new file mode 100644 index 00000000000000..c0104041b8b8c8 --- /dev/null +++ b/packages/icons/src/library/trending-down.js @@ -0,0 +1,12 @@ +/** + * WordPress dependencies + */ +import { SVG, Path } from '@wordpress/primitives'; + +const trendingDown = ( + <SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <Path d="M4.195 8.245a.75.75 0 011.06-.05l5.004 4.55 4.025-3.521L19 13.939V10.75h1.5v5.75h-5.75V15h3.19l-3.724-3.723-3.975 3.478-5.995-5.45a.75.75 0 01-.051-1.06z" /> + </SVG> +); + +export default trendingDown; diff --git a/packages/icons/src/library/trending-up.js b/packages/icons/src/library/trending-up.js new file mode 100644 index 00000000000000..ab1a5e53d1581a --- /dev/null +++ b/packages/icons/src/library/trending-up.js @@ -0,0 +1,12 @@ +/** + * WordPress dependencies + */ +import { SVG, Path } from '@wordpress/primitives'; + +const trendingUp = ( + <SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <Path d="M3.445 16.505a.75.75 0 001.06.05l5.005-4.55 4.024 3.521 4.716-4.715V14h1.5V8.25H14v1.5h3.19l-3.724 3.723L9.49 9.995l-5.995 5.45a.75.75 0 00-.05 1.06z" /> + </SVG> +); + +export default trendingUp; diff --git a/packages/icons/src/library/typography.js b/packages/icons/src/library/typography.js new file mode 100644 index 00000000000000..944a559207567f --- /dev/null +++ b/packages/icons/src/library/typography.js @@ -0,0 +1,12 @@ +/** + * WordPress dependencies + */ +import { SVG, Path } from '@wordpress/primitives'; + +const typography = ( + <SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <Path d="M6.9 7L3 17.8h1.7l1-2.8h4.1l1 2.8h1.7L8.6 7H6.9zm-.7 6.6l1.5-4.3 1.5 4.3h-3zM21.6 17c-.1.1-.2.2-.3.2-.1.1-.2.1-.4.1s-.3-.1-.4-.2c-.1-.1-.1-.3-.1-.6V12c0-.5 0-1-.1-1.4-.1-.4-.3-.7-.5-1-.2-.2-.5-.4-.9-.5-.4 0-.8-.1-1.3-.1s-1 .1-1.4.2c-.4.1-.7.3-1 .4-.2.2-.4.3-.6.5-.1.2-.2.4-.2.7 0 .3.1.5.2.8.2.2.4.3.8.3.3 0 .6-.1.8-.3.2-.2.3-.4.3-.7 0-.3-.1-.5-.2-.7-.2-.2-.4-.3-.6-.4.2-.2.4-.3.7-.4.3-.1.6-.1.8-.1.3 0 .6 0 .8.1.2.1.4.3.5.5.1.2.2.5.2.9v1.1c0 .3-.1.5-.3.6-.2.2-.5.3-.9.4-.3.1-.7.3-1.1.4-.4.1-.8.3-1.1.5-.3.2-.6.4-.8.7-.2.3-.3.7-.3 1.2 0 .6.2 1.1.5 1.4.3.4.9.5 1.6.5.5 0 1-.1 1.4-.3.4-.2.8-.6 1.1-1.1 0 .4.1.7.3 1 .2.3.6.4 1.2.4.4 0 .7-.1.9-.2.2-.1.5-.3.7-.4h-.3zm-3-.9c-.2.4-.5.7-.8.8-.3.2-.6.2-.8.2-.4 0-.6-.1-.9-.3-.2-.2-.3-.6-.3-1.1 0-.5.1-.9.3-1.2s.5-.5.8-.7c.3-.2.7-.3 1-.5.3-.1.6-.3.7-.6v3.4z" /> + </SVG> +); + +export default typography; diff --git a/packages/interface/.npmrc b/packages/interface/.npmrc new file mode 100644 index 00000000000000..43c97e719a5a82 --- /dev/null +++ b/packages/interface/.npmrc @@ -0,0 +1 @@ +package-lock=false diff --git a/packages/interface/CHANGELOG.md b/packages/interface/CHANGELOG.md new file mode 100644 index 00000000000000..e597eb0e1e333d --- /dev/null +++ b/packages/interface/CHANGELOG.md @@ -0,0 +1,3 @@ +## Master + +Initial release. diff --git a/packages/interface/README.md b/packages/interface/README.md new file mode 100644 index 00000000000000..21fc84ab45acf5 --- /dev/null +++ b/packages/interface/README.md @@ -0,0 +1,62 @@ +# (Experimental) Interface + +The Interface Package contains the basis the start a new WordPress screen as Edit Post or Edit Site. The package offers a data store and a set of components. The store is useful to contain common data required by a screen (e.g., active areas). The information is persisted across screen reloads. The components allow one to implement functionality like a sidebar or menu items. Third-party plugins by default, can extend them. + +## Installation + +Install the module + +```bash +npm install @wordpress/interface --save +``` + +_This package assumes that your code will run in an **ES2015+** environment. If you're using an environment that has limited or no support for ES2015+ such as lower versions of IE then using [core-js](https://github.com/zloirock/core-js) or [@babel/polyfill](https://babeljs.io/docs/en/next/babel-polyfill) will add support for these methods. Learn more about it in [Babel docs](https://babeljs.io/docs/en/next/caveats)._ + + +## API Usage + +### Complementary Areas + +This component was named after a [complementatry landmark](https://www.w3.org/TR/wai-aria-practices/examples/landmarks/complementary.html) – a supporting section of the document, designed to be complementary to the main content at a similar level in the DOM hierarchy, but remains meaningful when separated from the main content. + +`ComplementaryArea` and `ComplementaryArea.Slot` form a slot fill pair to render complementary areas. Multiple `ComplementaryArea` components representing different complementary areas may be rendered at the same time, but only one appears on the slot depending on which complementary area is enabled. + +It is possible to control which complementary is enabled by using the store: + +Bellow are some examples of how to control the active complementary area using the store: +```js +wp.data.select( 'core/interface' ).getActiveComplementaryArea( 'core/edit-post' ); +// -> "edit-post/document" + +wp.data.dispatch( 'core/interface' ).enableComplementaryArea( 'core/edit-post', 'edit-post/block' ); + +wp.data.select( 'core/interface' ).getActiveComplementaryArea( 'core/edit-post' ); +// -> "edit-post/block" + +wp.data.dispatch( 'core/interface' ).disableComplementaryArea( 'core/edit-post' ); + +wp.data.select( 'core/interface' ).getActiveComplementaryArea( 'core/edit-post' ); +// -> null +``` + +### Pinned Items + +`PinnedItems` and `PinnedItems.Slot` form a slot fill pair to render pinned items (or areas) that act as a list of favorites similar to browser extensions listed in the Chrome Menu. + +Example usage: `ComplementaryArea` component makes use of `PinnedItems` and automatically adds a pinned item for the complementary areas marked as a favorite. + +```js +wp.data.select( 'core/interface' ).isItemPinned( 'core/edit-post', 'edit-post-block-patterns/block-patterns-sidebar' ); +// -> false + +wp.data.dispatch( 'core/interface' ).pinItem( 'core/edit-post', 'edit-post-block-patterns/block-patterns-sidebar' ); + +wp.data.select( 'core/interface' ).isItemPinned( 'core/edit-post', 'edit-post-block-patterns/block-patterns-sidebar' ); +// -> true + +wp.data.dispatch( 'core/interface' ).unpinItem( 'core/edit-post', 'edit-post-block-patterns/block-patterns-sidebar' ); + +wp.data.select( 'core/interface' ).isItemPinned( 'core/edit-post', 'edit-post-block-patterns/block-patterns-sidebar' ); -> false +``` + +<br/><br/><p align="center"><img src="https://s.w.org/style/images/codeispoetry.png?1" alt="Code is Poetry." /></p> diff --git a/packages/interface/package.json b/packages/interface/package.json new file mode 100644 index 00000000000000..5397a0a823f94d --- /dev/null +++ b/packages/interface/package.json @@ -0,0 +1,38 @@ +{ + "name": "@wordpress/interface", + "version": "0.1.1", + "description": "Interface module for WordPress. The package contains shared functionality across the modern JavaScript-based WordPress screens.", + "author": "The WordPress Contributors", + "license": "GPL-2.0-or-later", + "keywords": [ + "wordpress", + "interface", + "components" + ], + "homepage": "https://github.com/WordPress/gutenberg/tree/master/packages/interface/README.md", + "repository": { + "type": "git", + "url": "https://github.com/WordPress/gutenberg.git", + "directory": "packages/interface" + }, + "bugs": { + "url": "https://github.com/WordPress/gutenberg/issues" + }, + "main": "build/index.js", + "module": "build-module/index.js", + "react-native": "src/index", + "dependencies": { + "@babel/runtime": "^7.9.2", + "@wordpress/components": "file:../components", + "@wordpress/data": "file:../data", + "@wordpress/element": "file:../element", + "@wordpress/i18n": "file:../i18n", + "@wordpress/icons": "file:../icons", + "@wordpress/plugins": "file:../plugins", + "classnames": "^2.2.5", + "lodash": "^4.17.15" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/interface/src/components/complementary-area-header/index.js b/packages/interface/src/components/complementary-area-header/index.js new file mode 100644 index 00000000000000..8e284fb4f2808c --- /dev/null +++ b/packages/interface/src/components/complementary-area-header/index.js @@ -0,0 +1,54 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + +/** + * WordPress dependencies + */ +import { Button } from '@wordpress/components'; +import { close } from '@wordpress/icons'; + +const ComplementaryAreaHeader = ( { + smallScreenTitle, + toggleShortcut, + onClose, + children, + className, + closeLabel, +} ) => { + return ( + <> + <div className="components-panel__header interface-complementary-area-header__small"> + { smallScreenTitle && ( + <span className="interface-complementary-area-header__small-title"> + { smallScreenTitle } + </span> + ) } + <Button + onClick={ onClose } + icon={ close } + label={ closeLabel } + /> + </div> + <div + className={ classnames( + 'components-panel__header', + 'interface-complementary-area-header', + className + ) } + tabIndex={ -1 } + > + { children } + <Button + onClick={ onClose } + icon={ close } + label={ closeLabel } + shortcut={ toggleShortcut } + /> + </div> + </> + ); +}; + +export default ComplementaryAreaHeader; diff --git a/packages/edit-post/src/components/sidebar/sidebar-header/style.scss b/packages/interface/src/components/complementary-area-header/style.scss similarity index 71% rename from packages/edit-post/src/components/sidebar/sidebar-header/style.scss rename to packages/interface/src/components/complementary-area-header/style.scss index aac3b2630f9a73..7808bc904ad230 100644 --- a/packages/edit-post/src/components/sidebar/sidebar-header/style.scss +++ b/packages/interface/src/components/complementary-area-header/style.scss @@ -1,9 +1,8 @@ -/* Text Editor specific */ -.components-panel__header.edit-post-sidebar-header__small { +.components-panel__header.interface-complementary-area-header__small { background: $white; padding-right: $grid-unit-05; - .edit-post-sidebar__title { + .interface-complementary-area-header__small-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; @@ -15,7 +14,7 @@ } } -.components-panel__header.edit-post-sidebar-header { +.interface-complementary-area-header { padding-right: $grid-unit-05; background: $light-gray-200; diff --git a/packages/interface/src/components/complementary-area/README.md b/packages/interface/src/components/complementary-area/README.md new file mode 100644 index 00000000000000..e44aaccb6b71cd --- /dev/null +++ b/packages/interface/src/components/complementary-area/README.md @@ -0,0 +1,115 @@ +ComplementaryArea +============================= + +`ComplementaryArea` is a component to render complementary areas like sidebars. Its implementation is based on slot & fill. +Multiple areas may be added in a given time, but only one is visible; the component renders the required artifacts to control which area is visible. The component allows, for example, to have multiple plugins rendering their sidebars, the user only sees one of the sidebars, but can switch which sidebar is active. + +The contents passed to ComplementaryArea are rendered in the ComplementaryArea.Slot corresponding to their scope if the complementary area is enabled. + +Besides rendering the complimentary area, the component renders a button in `PinnedItems` that allows opening the complementary area. The button only appears if the complementary is marked as favorite. By default, the complementary area headers rendered contain a button to mark and unmark areas as favorites. + +## Props + +### children + +The content to be displayed within the complementary area. + +- Type: `Element` +- Required: Yes + +### closeLabel + +Label of the button that allows to close the complementary area. + +- Type: `String` +- Required: No +- Default: "Close plugin" + +### complementaryAreaIdentifier + +Identifier of the complementary area. The string is saved on the store and allows to identify which of the sidebars is active. + +- Type: `String` +- Required: No +- Default: Concatenation of `name` of the plugin extracted from the context (when available) with the "name" of the sidebar passed as a property. + +### header + +In cases where a custom header is desirable, the prop could be used. It can contain the contents that should be drawn on the header. + +- Type: `Element` +- Required: No + +### headerClassName + +A className passed to the header container. + +- Type: `String` +- Required: No + +### icon + +The icon to render. + +- Type: `Function|WPComponent|null` +- Required: No +- Default: `null` + +### name + +Name of the complementary area. The name of the complementarity area is concatenated with the name of the plugin to form the identifier of the complementary area. The name of the plugin is extracted from the plugin context where the sidebar is rendered. If there is no plugin context available or there is a need to specify a custom identifier, please use the `complementaryAreaIdentifier` property instead. + +- Type: `String` +- Required: No + +### panelClassName + +A className passed to the panel that contains the contents of the sidebar. + +- Type: `String` +- Required: No +- Default: `null` + +### scope + +The scope of the complementary area e.g: "core/edit-post", "core/edit-site", "myplugin/custom-screen-a", + +- Type: `String` +- Required: Yes + +### smallScreenTitle + +In small screens, the complementary area may take up the entire screen. +`smallScreenTitle` allows displaying a title above the complementary area, so the user is more aware of what the area refers to. + +- Type: `String` +- Required: No + +### title + +Human friendly title of the complementary area. + +- Type: `String` +- Required: Yes + +### toggleShortcut + +Keyboard shortcut that allows opening and closing the area. Passed to the button that allows the same action, so the user sees a visual indication that there is a keyboard shortcut. + +- Type: `String|Object` +- Required: No + +ComplementaryArea.Slot +============================= + +A slot that renders the currently active ComplementaryArea. + +## Props + +### scope + +The scope of the complementary area e.g: "core/edit-post", "core/edit-site", "myplugin/custom-screen-a", + +- Type: `String` +- Required: Yes + diff --git a/packages/interface/src/components/complementary-area/index.js b/packages/interface/src/components/complementary-area/index.js new file mode 100644 index 00000000000000..2a60be08d3b456 --- /dev/null +++ b/packages/interface/src/components/complementary-area/index.js @@ -0,0 +1,148 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + +/** + * WordPress dependencies + */ +import { Animate, Button, Panel, Slot, Fill } from '@wordpress/components'; +import { useDispatch, useSelect } from '@wordpress/data'; +import { __ } from '@wordpress/i18n'; +import { withPluginContext } from '@wordpress/plugins'; +import { starEmpty, starFilled } from '@wordpress/icons'; + +/** + * Internal dependencies + */ +import ComplementaryAreaHeader from '../complementary-area-header'; +import PinnedItems from '../pinned-items'; + +function ComplementaryAreaSlot( { scope, ...props } ) { + return <Slot name={ `ComplementaryArea/${ scope }` } { ...props } />; +} + +function ComplementaryAreaFill( { scope, children, className } ) { + return ( + <Fill name={ `ComplementaryArea/${ scope }` }> + <Animate type="slide-in" options={ { origin: 'left' } }> + { () => <div className={ className }>{ children }</div> } + </Animate> + </Fill> + ); +} + +function ComplementaryArea( { + children, + className, + closeLabel = __( 'Close plugin' ), + complementaryAreaIdentifier, + header, + headerClassName, + icon, + isPinnable = true, + panelClassName, + scope, + smallScreenTitle, + title, + toggleShortcut, +} ) { + const { isActive, isPinned } = useSelect( + ( select ) => { + const { getActiveComplementaryArea, isItemPinned } = select( + 'core/interface' + ); + return { + isActive: + getActiveComplementaryArea( scope ) === + complementaryAreaIdentifier, + isPinned: isItemPinned( scope, complementaryAreaIdentifier ), + }; + }, + [ complementaryAreaIdentifier, scope ] + ); + const { enableComplementaryArea, disableComplementaryArea } = useDispatch( + 'core/interface' + ); + const { pinItem, unpinItem } = useDispatch( 'core/interface' ); + return ( + <> + { isPinned && isPinnable && ( + <PinnedItems scope={ scope }> + <Button + icon={ icon } + label={ title } + onClick={ () => + isActive + ? disableComplementaryArea( scope ) + : enableComplementaryArea( + scope, + complementaryAreaIdentifier + ) + } + isPressed={ isActive } + aria-expanded={ isActive } + /> + </PinnedItems> + ) } + { isActive && ( + <ComplementaryAreaFill + className={ classnames( + 'interface-complementary-area', + className + ) } + scope={ scope } + > + <ComplementaryAreaHeader + className={ headerClassName } + closeLabel={ closeLabel } + onClose={ () => disableComplementaryArea( scope ) } + smallScreenTitle={ smallScreenTitle } + toggleShortcut={ toggleShortcut } + > + { header || ( + <> + <strong>{ title }</strong> + { isPinnable && ( + <Button + className="interface-complementary-area__pin-unpin-item" + icon={ + isPinned ? starFilled : starEmpty + } + label={ + isPinned + ? __( 'Unpin from toolbar' ) + : __( 'Pin to toolbar' ) + } + onClick={ () => + ( isPinned ? unpinItem : pinItem )( + scope, + complementaryAreaIdentifier + ) + } + isPressed={ isPinned } + aria-expanded={ isPinned } + /> + ) } + </> + ) } + </ComplementaryAreaHeader> + <Panel className={ panelClassName }>{ children }</Panel> + </ComplementaryAreaFill> + ) } + </> + ); +} + +const ComplementaryAreaWrapped = withPluginContext( ( context, ownProps ) => { + return { + icon: ownProps.icon || context.icon, + complementaryAreaIdentifier: + ownProps.complementaryAreaIdentifier || + `${ context.name }/${ ownProps.name }`, + }; +} )( ComplementaryArea ); + +ComplementaryAreaWrapped.Slot = ComplementaryAreaSlot; + +export default ComplementaryAreaWrapped; diff --git a/packages/interface/src/components/complementary-area/style.scss b/packages/interface/src/components/complementary-area/style.scss new file mode 100644 index 00000000000000..469e6605d13d5f --- /dev/null +++ b/packages/interface/src/components/complementary-area/style.scss @@ -0,0 +1,82 @@ +.interface-complementary-area { + background: $white; + color: $dark-gray-500; + overflow: visible; + + @include break-small() { + z-index: auto; + height: 100%; + overflow: auto; + -webkit-overflow-scrolling: touch; + } + + @include break-medium() { + width: $sidebar-width; + } + + > .components-panel { + border-left: none; + border-right: none; + overflow: auto; + -webkit-overflow-scrolling: touch; + height: auto; + max-height: calc(100vh - #{ $admin-bar-height-big + $panel-header-height + $panel-header-height }); + margin-top: -1px; + margin-bottom: -1px; + position: relative; + + @include break-small() { + overflow: visible; + height: auto; + max-height: none; + } + } + + > .components-panel .components-panel__header { + position: fixed; + z-index: z-index(".components-panel__header"); + top: 0; + left: 0; + right: 0; + height: $panel-header-height; + + @include break-small() { + position: inherit; + top: auto; + left: auto; + right: auto; + } + } + + p { + margin-top: 0; + } + + h2, + h3 { + font-size: $default-font-size; + color: $dark-gray-500; + margin-bottom: 1.5em; + } + + hr { + border-top: none; + border-bottom: 1px solid $light-gray-500; + margin: 1.5em 0; + } + + div.components-toolbar { + box-shadow: none; + margin-bottom: 1.5em; + &:last-child { + margin-bottom: 0; + } + } + + .block-editor-skip-to-selected-block:focus { + top: auto; + right: 10px; + bottom: 10px; + left: auto; + } +} diff --git a/packages/block-editor/src/components/fullscreen-mode/index.js b/packages/interface/src/components/fullscreen-mode/index.js similarity index 100% rename from packages/block-editor/src/components/fullscreen-mode/index.js rename to packages/interface/src/components/fullscreen-mode/index.js diff --git a/packages/interface/src/components/fullscreen-mode/style.scss b/packages/interface/src/components/fullscreen-mode/style.scss new file mode 100644 index 00000000000000..9489a9f6f96512 --- /dev/null +++ b/packages/interface/src/components/fullscreen-mode/style.scss @@ -0,0 +1,19 @@ +body.js.is-fullscreen-mode { + + @include break-medium { + // Reset the html.wp-topbar padding. + // Because this uses negative margins, we have to compensate for the height. + margin-top: -$admin-bar-height; + height: calc(100% + #{ $admin-bar-height }); + + #adminmenumain, + #wpadminbar { + display: none; + } + + #wpcontent, + #wpfooter { + margin-left: 0; + } + } +} diff --git a/packages/block-editor/src/components/fullscreen-mode/test/index.js b/packages/interface/src/components/fullscreen-mode/test/index.js similarity index 100% rename from packages/block-editor/src/components/fullscreen-mode/test/index.js rename to packages/interface/src/components/fullscreen-mode/test/index.js diff --git a/packages/interface/src/components/index.js b/packages/interface/src/components/index.js new file mode 100644 index 00000000000000..9071a42c0ff944 --- /dev/null +++ b/packages/interface/src/components/index.js @@ -0,0 +1,4 @@ +export { default as ComplementaryArea } from './complementary-area'; +export { default as FullscreenMode } from './fullscreen-mode'; +export { default as InterfaceSkeleton } from './interface-skeleton'; +export { default as PinnedItems } from './pinned-items'; diff --git a/packages/interface/src/components/index.native.js b/packages/interface/src/components/index.native.js new file mode 100644 index 00000000000000..460408d4bf2f12 --- /dev/null +++ b/packages/interface/src/components/index.native.js @@ -0,0 +1,2 @@ +export { default as ComplementaryArea } from './complementary-area'; +export { default as PinnedItems } from './pinned-items'; diff --git a/packages/interface/src/components/interface-skeleton/index.js b/packages/interface/src/components/interface-skeleton/index.js new file mode 100644 index 00000000000000..7ba335b9dffa6e --- /dev/null +++ b/packages/interface/src/components/interface-skeleton/index.js @@ -0,0 +1,127 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + +/** + * WordPress dependencies + */ +import { useEffect } from '@wordpress/element'; +import { navigateRegions } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; + +function useHTMLClass( className ) { + useEffect( () => { + const element = + document && document.querySelector( `html:not(.${ className })` ); + if ( ! element ) { + return; + } + element.classList.toggle( className ); + return () => { + element.classList.toggle( className ); + }; + }, [ className ] ); +} + +function InterfaceSkeleton( { + footer, + header, + sidebar, + leftSidebar, + content, + actions, + labels, + className, +} ) { + useHTMLClass( 'interface-interface-skeleton__html-container' ); + + const defaultLabels = { + /* translators: accessibility text for the top bar landmark region. */ + header: __( 'Header' ), + /* translators: accessibility text for the content landmark region. */ + body: __( 'Content' ), + /* translators: accessibility text for the left sidebar landmark region. */ + leftSidebar: __( 'Left sidebar' ), + /* translators: accessibility text for the settings landmark region. */ + sidebar: __( 'Settings' ), + /* translators: accessibility text for the publish landmark region. */ + actions: __( 'Publish' ), + /* translators: accessibility text for the footer landmark region. */ + footer: __( 'Footer' ), + }; + + const mergedLabels = { ...defaultLabels, ...labels }; + + return ( + <div + className={ classnames( + className, + 'interface-interface-skeleton' + ) } + > + { !! header && ( + <div + className="interface-interface-skeleton__header" + role="region" + aria-label={ mergedLabels.header } + tabIndex="-1" + > + { header } + </div> + ) } + <div className="interface-interface-skeleton__body"> + { !! leftSidebar && ( + <div + className="interface-interface-skeleton__left-sidebar" + role="region" + aria-label={ mergedLabels.leftSidebar } + tabIndex="-1" + > + { leftSidebar } + </div> + ) } + <div + className="interface-interface-skeleton__content" + role="region" + aria-label={ mergedLabels.body } + tabIndex="-1" + > + { content } + </div> + { !! sidebar && ( + <div + className="interface-interface-skeleton__sidebar" + role="region" + aria-label={ mergedLabels.sidebar } + tabIndex="-1" + > + { sidebar } + </div> + ) } + { !! actions && ( + <div + className="interface-interface-skeleton__actions" + role="region" + aria-label={ mergedLabels.actions } + tabIndex="-1" + > + { actions } + </div> + ) } + </div> + { !! footer && ( + <div + className="interface-interface-skeleton__footer" + role="region" + aria-label={ mergedLabels.footer } + tabIndex="-1" + > + { footer } + </div> + ) } + </div> + ); +} + +export default navigateRegions( InterfaceSkeleton ); diff --git a/packages/block-editor/src/components/editor-skeleton/style.scss b/packages/interface/src/components/interface-skeleton/style.scss similarity index 77% rename from packages/block-editor/src/components/editor-skeleton/style.scss rename to packages/interface/src/components/interface-skeleton/style.scss index 0d70dc621b8f10..b9095d2e5946bc 100644 --- a/packages/block-editor/src/components/editor-skeleton/style.scss +++ b/packages/interface/src/components/interface-skeleton/style.scss @@ -1,6 +1,6 @@ // On Mobile devices, swiping the HTML element should not scroll. // By making it fixed, we prevent that. -html.block-editor-editor-skeleton__html-container { +html.interface-interface-skeleton__html-container { position: fixed; width: 100%; @@ -10,7 +10,7 @@ html.block-editor-editor-skeleton__html-container { } } -.block-editor-editor-skeleton { +.interface-interface-skeleton { display: flex; flex-direction: column; height: auto; @@ -24,7 +24,7 @@ html.block-editor-editor-skeleton__html-container { bottom: 0; // Adjust to admin-bar going small. - @include break-medium() { + @media (min-width: #{ ($break-medium + 1) }) { top: $admin-bar-height; .is-fullscreen-mode & { @@ -33,9 +33,9 @@ html.block-editor-editor-skeleton__html-container { } } -@include editor-left(".block-editor-editor-skeleton"); +@include editor-left(".interface-interface-skeleton"); -.block-editor-editor-skeleton__body { +.interface-interface-skeleton__body { flex-grow: 1; display: flex; @@ -57,7 +57,7 @@ html.block-editor-editor-skeleton__html-container { overscroll-behavior-y: none; } -.block-editor-editor-skeleton__content { +.interface-interface-skeleton__content { flex-grow: 1; // Treat as flex container to allow children to grow to occupy full @@ -73,12 +73,13 @@ html.block-editor-editor-skeleton__html-container { } -.block-editor-editor-skeleton__sidebar { +.interface-interface-skeleton__left-sidebar, +.interface-interface-skeleton__sidebar { display: block; width: auto; // Keep the sidebar width flexible. flex-shrink: 0; position: absolute; - z-index: z-index(".block-editor-editor-skeleton__sidebar"); + z-index: z-index(".interface-interface-skeleton__sidebar"); top: 0; right: 0; bottom: 0; @@ -87,19 +88,30 @@ html.block-editor-editor-skeleton__html-container { color: $dark-gray-primary; // On Mobile the header is fixed to keep HTML as scrollable. + @include break-medium() { + position: relative !important; + z-index: z-index(".interface-interface-skeleton__sidebar {greater than small}"); + } +} + +.interface-interface-skeleton__sidebar { @include break-medium() { overflow: auto; border-left: $border-width solid $light-gray-500; - position: relative !important; - z-index: z-index(".block-editor-editor-skeleton__sidebar {greater than small}"); } } -.block-editor-editor-skeleton__header { +.interface-interface-skeleton__left-sidebar { + @include break-medium() { + border-right: $border-width solid $light-gray-500; + } +} + +.interface-interface-skeleton__header { flex-shrink: 0; height: auto; // Keep the height flexible. border-bottom: $border-width solid $light-gray-500; - z-index: z-index(".block-editor-editor-skeleton__header"); + z-index: z-index(".interface-interface-skeleton__header"); color: $dark-gray-primary; // On Mobile the header is sticky. @@ -113,7 +125,7 @@ html.block-editor-editor-skeleton__html-container { } } -.block-editor-editor-skeleton__footer { +.interface-interface-skeleton__footer { height: auto; // Keep the height flexible. flex-shrink: 0; border-top: $border-width solid $light-gray-500; @@ -126,9 +138,9 @@ html.block-editor-editor-skeleton__html-container { } } -.block-editor-editor-skeleton__publish { - z-index: z-index(".block-editor-editor-skeleton__publish"); - position: fixed !important; // Need to override the default relative positionning +.interface-interface-skeleton__actions { + z-index: z-index(".interface-interface-skeleton__actions"); + position: fixed !important; // Need to override the default relative positioning top: -9999em; bottom: auto; left: auto; diff --git a/packages/interface/src/components/pinned-items/README.md b/packages/interface/src/components/pinned-items/README.md new file mode 100644 index 00000000000000..0bf15513480417 --- /dev/null +++ b/packages/interface/src/components/pinned-items/README.md @@ -0,0 +1,38 @@ +PinnedItems +============================= + +There are situations where a screen has an area for favorites or pinned items. +This Component allows adding items to that area. Most of the time, the Component should not be used directly as, for example, `ComplementaryArea` Component already renders PinnedItems that allow opening complementary areas marked as favorite. +When used directly, items should not unconditionally add items should only be added if they are marked as "favorite" or verify other conditions. + +## Props + +### children + +The content to be displayed for the pinned items. Most of the time, a button with an icon should be used. + +- Type: `Element` +- Required: Yes + +### scope + +The scope of the pinned items area e.g: "core/edit-post", "core/edit-site", "myplugin/custom-screen-a", + +- Type: `String` +- Required: Yes + +PinnedItems.Slot +============================= + +A slot that renders the pinned items. + +## Props + +### scope + +The scope of the pinned items area e.g: "core/edit-post", "core/edit-site", "myplugin/custom-screen-a", + +- Type: `String` +- Required: Yes + + diff --git a/packages/interface/src/components/pinned-items/index.js b/packages/interface/src/components/pinned-items/index.js new file mode 100644 index 00000000000000..59fc70003095bb --- /dev/null +++ b/packages/interface/src/components/pinned-items/index.js @@ -0,0 +1,37 @@ +/** + * External dependencies + */ +import { isEmpty } from 'lodash'; +import classnames from 'classnames'; + +/** + * WordPress dependencies + */ +import { Slot, Fill } from '@wordpress/components'; + +function PinnedItems( { scope, ...props } ) { + return <Fill name={ `PinnedItems/${ scope }` } { ...props } />; +} + +function PinnedItemsSlot( { scope, className, ...props } ) { + return ( + <Slot name={ `PinnedItems/${ scope }` } { ...props }> + { ( fills ) => + ! isEmpty( fills ) && ( + <div + className={ classnames( + className, + 'interface-pinned-items' + ) } + > + { fills } + </div> + ) + } + </Slot> + ); +} + +PinnedItems.Slot = PinnedItemsSlot; + +export default PinnedItems; diff --git a/packages/interface/src/components/pinned-items/style.scss b/packages/interface/src/components/pinned-items/style.scss new file mode 100644 index 00000000000000..76f0fe87fa25a0 --- /dev/null +++ b/packages/interface/src/components/pinned-items/style.scss @@ -0,0 +1,20 @@ +.interface-pinned-items { + display: none; + + @include break-small() { + display: flex; + } + + .components-button { + margin-left: 4px; + + &.is-pressed { + margin-left: 5px; + } + + svg { + max-width: 24px; + max-height: 24px; + } + } +} diff --git a/packages/interface/src/index.js b/packages/interface/src/index.js new file mode 100644 index 00000000000000..7b5bd2101b7195 --- /dev/null +++ b/packages/interface/src/index.js @@ -0,0 +1,6 @@ +/** + * Internal dependencies + */ +import './store'; + +export * from './components'; diff --git a/packages/interface/src/store/actions.js b/packages/interface/src/store/actions.js new file mode 100644 index 00000000000000..ae01f9945e1487 --- /dev/null +++ b/packages/interface/src/store/actions.js @@ -0,0 +1,84 @@ +/** + * Returns an action object used in signalling that an active area should be changed. + * + * @param {string} itemType Type of item. + * @param {string} scope Item scope. + * @param {string} item Item identifier. + * + * @return {Object} Action object. + */ +function setSingleEnableItem( itemType, scope, item ) { + return { + type: 'SET_SINGLE_ENABLE_ITEM', + itemType, + scope, + item, + }; +} + +/** + * Returns an action object used in signalling that a complementary item should be enabled. + * + * @param {string} scope Complementary area scope. + * @param {string} area Area identifier. + * + * @return {Object} Action object. + */ +export function enableComplementaryArea( scope, area ) { + return setSingleEnableItem( 'complementaryArea', scope, area ); +} + +/** + * Returns an action object used in signalling that the complementary area of a given scope should be disabled. + * + * @param {string} scope Complementary area scope. + * + * @return {Object} Action object. + */ +export function disableComplementaryArea( scope ) { + return setSingleEnableItem( 'complementaryArea', scope, undefined ); +} + +/** + * Returns an action object to make an area enabled/disabled. + * + * @param {string} itemType Type of item. + * @param {string} scope Item scope. + * @param {string} item Item identifier. + * @param {boolean} isEnable Boolean indicating if an area should be pinned or not. + * + * @return {Object} Action object. + */ +function setMultipleEnableItem( itemType, scope, item, isEnable ) { + return { + type: 'SET_MULTIPLE_ENABLE_ITEM', + itemType, + scope, + item, + isEnable, + }; +} + +/** + * Returns an action object used in signalling that an item should be pinned. + * + * @param {string} scope Item scope. + * @param {string} itemId Item identifier. + * + * @return {Object} Action object. + */ +export function pinItem( scope, itemId ) { + return setMultipleEnableItem( 'pinnedItems', scope, itemId, true ); +} + +/** + * Returns an action object used in signalling that an item should be unpinned. + * + * @param {string} scope Item scope. + * @param {string} itemId Item identifier. + * + * @return {Object} Action object. + */ +export function unpinItem( scope, itemId ) { + return setMultipleEnableItem( 'pinnedItems', scope, itemId, false ); +} diff --git a/packages/interface/src/store/constants.js b/packages/interface/src/store/constants.js new file mode 100644 index 00000000000000..ad82e7c6a6d755 --- /dev/null +++ b/packages/interface/src/store/constants.js @@ -0,0 +1,6 @@ +/** + * The identifier for the data store. + * + * @type {string} + */ +export const STORE_KEY = 'core/interface'; diff --git a/packages/interface/src/store/defaults.js b/packages/interface/src/store/defaults.js new file mode 100644 index 00000000000000..03d79595552b1e --- /dev/null +++ b/packages/interface/src/store/defaults.js @@ -0,0 +1,10 @@ +export const DEFAULTS = { + enableItems: { + singleEnableItems: { + complementaryArea: { + 'core/edit-site': 'edit-site/block-inspector', + 'core/edit-post': 'edit-post/document', + }, + }, + }, +}; diff --git a/packages/interface/src/store/defaults.native.js b/packages/interface/src/store/defaults.native.js new file mode 100644 index 00000000000000..730ef449dde23c --- /dev/null +++ b/packages/interface/src/store/defaults.native.js @@ -0,0 +1,10 @@ +export const DEFAULTS = { + enableItems: { + singleEnableItems: { + complementaryArea: {}, + }, + multipleEnableItems: { + pinnedItems: {}, + }, + }, +}; diff --git a/packages/edit-post/src/store/index.native.js b/packages/interface/src/store/index.js similarity index 59% rename from packages/edit-post/src/store/index.native.js rename to packages/interface/src/store/index.js index 10355071bd454a..12c723cd51b04e 100644 --- a/packages/edit-post/src/store/index.native.js +++ b/packages/interface/src/store/index.js @@ -7,7 +7,6 @@ import { registerStore } from '@wordpress/data'; * Internal dependencies */ import reducer from './reducer'; -import applyMiddlewares from './middlewares'; import * as actions from './actions'; import * as selectors from './selectors'; import { STORE_KEY } from './constants'; @@ -16,11 +15,7 @@ const store = registerStore( STORE_KEY, { reducer, actions, selectors, - persist: [ 'preferences' ], + persist: [ 'enableItems' ], } ); -applyMiddlewares( store ); -// Do not dispatch INIT for mobile as its effect currently only deals with -// setting up the sidebar and we don't need/support it at the moment for mobile - export default store; diff --git a/packages/interface/src/store/reducer.js b/packages/interface/src/store/reducer.js new file mode 100644 index 00000000000000..fbd4f341500ca4 --- /dev/null +++ b/packages/interface/src/store/reducer.js @@ -0,0 +1,110 @@ +/** + * External dependencies + */ +import { flow, get, isEmpty, omit } from 'lodash'; + +/** + * WordPress dependencies + */ +import { combineReducers } from '@wordpress/data'; + +/** + * Internal dependencies + */ +import { DEFAULTS } from './defaults'; + +/** + * Higher-order reducer creator which provides the given initial state for the + * original reducer. + * + * @param {*} initialState Initial state to provide to reducer. + * + * @return {Function} Higher-order reducer. + */ +const createWithInitialState = ( initialState ) => ( reducer ) => { + return ( state = initialState, action ) => reducer( state, action ); +}; + +/** + * Reducer to keep tract of the active area per scope. + * + * @param {boolean} state Previous state. + * @param {Object} action Action Object. + * + * @return {Object} Updated state. + */ +export function singleEnableItems( + state = {}, + { type, itemType, scope, item } +) { + if ( type !== 'SET_SINGLE_ENABLE_ITEM' || ! itemType || ! scope ) { + return state; + } + + if ( + ! item && + ! get( DEFAULTS.enableItems.singleEnableItems, [ itemType, scope ] ) + ) { + const newTypeState = omit( state[ itemType ], [ scope ] ); + return isEmpty( newTypeState ) + ? omit( state, [ itemType ] ) + : { + ...state, + [ itemType ]: newTypeState, + }; + } + return { + ...state, + [ itemType ]: { + ...state[ itemType ], + [ scope ]: item || null, + }, + }; +} + +/** + * Reducer keeping track of the "pinned" items per scope + * + * @param {boolean} state Previous state. + * @param {Object} action Action Object. + * + * @return {Object} Updated state. + */ +export function multipleEnableItems( + state = {}, + { type, itemType, scope, item, isEnable } +) { + if ( + type !== 'SET_MULTIPLE_ENABLE_ITEM' || + ! itemType || + ! scope || + ! item || + get( state, [ itemType, scope, item ] ) === isEnable + ) { + return state; + } + const currentTypeState = state[ itemType ] || {}; + const currentScopeState = currentTypeState[ scope ] || {}; + + return { + ...state, + [ itemType ]: { + ...currentTypeState, + [ scope ]: { + ...currentScopeState, + [ item ]: isEnable || false, + }, + }, + }; +} + +const enableItems = combineReducers( { + singleEnableItems, + multipleEnableItems, +} ); + +export default flow( [ combineReducers, createWithInitialState( DEFAULTS ) ] )( + { + enableItems, + } +); diff --git a/packages/interface/src/store/selectors.js b/packages/interface/src/store/selectors.js new file mode 100644 index 00000000000000..d273d96fead346 --- /dev/null +++ b/packages/interface/src/store/selectors.js @@ -0,0 +1,67 @@ +/** + * External dependencies + */ +import { get } from 'lodash'; + +/** + * Returns the item that is enabled in a given scope. + * + * @param {Object} state Global application state. + * @param {string} itemType Type of item. + * @param {string} scope Item scope. + * + * @return {string} The item that is enabled in the passed scope and type. + */ +function getSingleEnableItem( state, itemType, scope ) { + return get( + state.enableItems.singleEnableItems, + [ itemType, scope ], + null + ); +} + +/** + * Returns the complementary area that is active in a given scope. + * + * @param {Object} state Global application state. + * @param {string} scope Item scope. + * + * @return {string} The complementary area that is active in the given scope. + */ +export function getActiveComplementaryArea( state, scope ) { + return getSingleEnableItem( state, 'complementaryArea', scope ); +} + +/** + * Returns a boolean indicating if an item is enabled or not in a given scope. + * + * @param {Object} state Global application state. + * @param {string} itemType Type of item. + * @param {string} scope Scope. + * @param {string} item Item to check. + * + * @return {boolean|undefined} True if the item is enabled, false otherwise if the item is explicitly disabled, and undefined if there is no information for that item. + */ +function isMultipleEnabledItemEnabled( state, itemType, scope, item ) { + return get( state.enableItems.multipleEnableItems, [ + itemType, + scope, + item, + ] ); +} + +/** + * Returns a boolean indicating if an item is pinned or not. + * + * @param {Object} state Global application state. + * @param {string} scope Scope. + * @param {string} item Item to check. + * + * @return {boolean} True if the item is pinned and false otherwise. + */ +export function isItemPinned( state, scope, item ) { + return ( + isMultipleEnabledItemEnabled( state, 'pinnedItems', scope, item ) !== + false + ); +} diff --git a/packages/interface/src/style.scss b/packages/interface/src/style.scss new file mode 100644 index 00000000000000..d7f1e35e6e6616 --- /dev/null +++ b/packages/interface/src/style.scss @@ -0,0 +1,5 @@ +@import "./components/complementary-area-header/style.scss"; +@import "./components/complementary-area/style.scss"; +@import "./components/fullscreen-mode/style.scss"; +@import "./components/interface-skeleton/style.scss"; +@import "./components/pinned-items/style.scss"; diff --git a/packages/is-shallow-equal/CHANGELOG.md b/packages/is-shallow-equal/CHANGELOG.md index 17019daee1ea6b..f85ccb265d14e0 100644 --- a/packages/is-shallow-equal/CHANGELOG.md +++ b/packages/is-shallow-equal/CHANGELOG.md @@ -1,3 +1,17 @@ +## Master + +## 2.0.0 (2020-04-15) + +### Breaking Change + +- Restructure package moving source files into `lib` directory. Direct imports of + `@wordpress/is-shallow-equal/arrays` and `@wordpress/is-shallow-equal/objects` were never + officially supported and have been removed. ([#18942](https://github.com/WordPress/gutenberg/pull/18942)) + +### New feature + +- Include TypeScript type declarations ([#18942](https://github.com/WordPress/gutenberg/pull/18942)) + ## 1.5.0 (2019-08-05) ### Bug Fixes diff --git a/packages/is-shallow-equal/benchmark/index.js b/packages/is-shallow-equal/benchmark/index.js index 5506e53206e129..5779f87688eae3 100644 --- a/packages/is-shallow-equal/benchmark/index.js +++ b/packages/is-shallow-equal/benchmark/index.js @@ -16,10 +16,10 @@ const afterArrayUnequal = [ 1, 2, 3, 4, 5, 'Unequal', 7 ]; [ [ '@wordpress/is-shallow-equal (type specific)', - require( '../objects' ), - require( '../arrays' ), + require( '..' ).isShallowEqualObjects, + require( '..' ).isShallowEqualArrays, ], - [ '@wordpress/is-shallow-equal', require( '../' ) ], + [ '@wordpress/is-shallow-equal', require( '..' ) ], [ 'shallowequal', require( 'shallowequal' ) ], [ 'shallow-equal (type specific)', diff --git a/packages/is-shallow-equal/arrays.js b/packages/is-shallow-equal/lib/arrays.js similarity index 100% rename from packages/is-shallow-equal/arrays.js rename to packages/is-shallow-equal/lib/arrays.js diff --git a/packages/is-shallow-equal/index.js b/packages/is-shallow-equal/lib/index.js similarity index 94% rename from packages/is-shallow-equal/index.js rename to packages/is-shallow-equal/lib/index.js index dc9c074f8327e2..3469656d020376 100644 --- a/packages/is-shallow-equal/index.js +++ b/packages/is-shallow-equal/lib/index.js @@ -9,7 +9,7 @@ var isShallowEqualArrays = require( './arrays' ); var isArray = Array.isArray; /** - * @typedef {{[key: string]: any}} ComparableObject + * @typedef {Record<string, any>} ComparableObject */ /** diff --git a/packages/is-shallow-equal/objects.js b/packages/is-shallow-equal/lib/objects.js similarity index 100% rename from packages/is-shallow-equal/objects.js rename to packages/is-shallow-equal/lib/objects.js diff --git a/packages/is-shallow-equal/package.json b/packages/is-shallow-equal/package.json index 0800bdb4e75437..59d9c376fb3f7a 100644 --- a/packages/is-shallow-equal/package.json +++ b/packages/is-shallow-equal/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/is-shallow-equal", - "version": "1.8.0", + "version": "2.0.0", "description": "Test for shallow equality between two objects or arrays.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -20,14 +20,15 @@ "url": "https://github.com/WordPress/gutenberg/issues" }, "files": [ - "arrays.js", - "index.js", - "objects.js" + "lib", + "build-types", + "*.md" ], - "main": "index.js", + "main": "lib/index.js", + "types": "build-types", "sideEffects": false, "dependencies": { - "@babel/runtime": "^7.8.3" + "@babel/runtime": "^7.9.2" }, "publishConfig": { "access": "public" diff --git a/packages/is-shallow-equal/test/index.js b/packages/is-shallow-equal/test/index.js index 3ec86ed3529287..66bf538552c645 100644 --- a/packages/is-shallow-equal/test/index.js +++ b/packages/is-shallow-equal/test/index.js @@ -1,9 +1,10 @@ /** * Internal dependencies */ -import isShallowEqual from '../'; -import isShallowEqualArrays from '../arrays'; -import isShallowEqualObjects from '../objects'; +import isShallowEqual, { + isShallowEqualArrays, + isShallowEqualObjects, +} from '..'; describe( 'isShallowEqual', () => { it( 'returns false if of different types', () => { diff --git a/packages/is-shallow-equal/tsconfig.json b/packages/is-shallow-equal/tsconfig.json new file mode 100644 index 00000000000000..426ab13d0aa8f6 --- /dev/null +++ b/packages/is-shallow-equal/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "lib", + "declarationDir": "build-types" + }, + "include": [ "lib/**/*" ] +} diff --git a/packages/jest-console/package.json b/packages/jest-console/package.json index 1403c4b16d858c..72f17d9d307ed0 100644 --- a/packages/jest-console/package.json +++ b/packages/jest-console/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/jest-console", - "version": "3.5.0", + "version": "3.6.0", "description": "Custom Jest matchers for the Console object.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -29,8 +29,8 @@ "main": "build/index.js", "module": "build-module/index.js", "dependencies": { - "@babel/runtime": "^7.8.3", - "jest-matcher-utils": "^24.7.0", + "@babel/runtime": "^7.9.2", + "jest-matcher-utils": "^25.3.0", "lodash": "^4.17.15" }, "peerDependencies": { diff --git a/packages/jest-console/src/test/index.test.js b/packages/jest-console/src/test/index.test.js index 490e3242070c17..caebf6915ab5c8 100644 --- a/packages/jest-console/src/test/index.test.js +++ b/packages/jest-console/src/test/index.test.js @@ -71,15 +71,20 @@ describe( 'jest-console', () => { describe( 'lifecycle', () => { beforeAll( () => { + // Disable reason: // This is a difficult one to test, since the matcher's // own lifecycle is defined to run before ours. Infer // that we're being watched by testing the console // method as being a spy. + // eslint-disable-next-line jest/no-standalone-expect expect( console[ methodName ].assertionsNumber ).toBeGreaterThanOrEqual( 0 ); } ); + // Disable reason: + // See beforeAll implementation and explanation added there. + // eslint-disable-next-line jest/expect-expect it( 'captures logging in lifecycle', () => {} ); } ); } ); diff --git a/packages/jest-preset-default/CHANGELOG.md b/packages/jest-preset-default/CHANGELOG.md index 6113ac0aba4d7c..0c26af370bd2ea 100644 --- a/packages/jest-preset-default/CHANGELOG.md +++ b/packages/jest-preset-default/CHANGELOG.md @@ -1,5 +1,12 @@ ## Master +## 6.0.0 (2020-04-15) + +### Breaking Changes + +- The peer `jest` dependency has been updated from requiring `>=24` to requiring `>=25` (see [Breaking Changes](https://jestjs.io/blog/2020/01/21/jest-25), [#20766](https://github.com/WordPress/gutenberg/pull/20766)). +- This package requires now `node` v10.0.0 or later ([#20766](https://github.com/WordPress/gutenberg/pull/20766)). + ## 5.4.0 (2020-02-04) ### Bug Fixes diff --git a/packages/jest-preset-default/package.json b/packages/jest-preset-default/package.json index f21666ff2f55a6..e7bd4f50a52383 100644 --- a/packages/jest-preset-default/package.json +++ b/packages/jest-preset-default/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/jest-preset-default", - "version": "5.4.0", + "version": "6.0.0", "description": "Default Jest preset for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -22,7 +22,7 @@ "url": "https://github.com/WordPress/gutenberg/issues" }, "engines": { - "node": ">=8" + "node": ">=10" }, "files": [ "scripts", @@ -31,15 +31,15 @@ ], "main": "index.js", "dependencies": { - "@jest/reporters": "^24.8.0", + "@jest/reporters": "^25.3.0", "@wordpress/jest-console": "file:../jest-console", - "babel-jest": "^24.9.0", - "enzyme": "^3.9.0", - "enzyme-adapter-react-16": "^1.10.0", - "enzyme-to-json": "^3.3.5" + "babel-jest": "^25.3.0", + "enzyme": "^3.11.0", + "enzyme-adapter-react-16": "^1.15.2", + "enzyme-to-json": "^3.4.4" }, "peerDependencies": { - "jest": ">=24" + "jest": ">=25" }, "publishConfig": { "access": "public" diff --git a/packages/jest-puppeteer-axe/CHANGELOG.md b/packages/jest-puppeteer-axe/CHANGELOG.md index 1d1fe3ca36aeb7..61266033660bbc 100644 --- a/packages/jest-puppeteer-axe/CHANGELOG.md +++ b/packages/jest-puppeteer-axe/CHANGELOG.md @@ -1,3 +1,9 @@ +## Master + +## New Features + +- The `axe-puppeteer` dependency has been updated from requiring `^1.0.0` to requiring `^1.1.0`. + ## 1.1.0 (2019-05-21) ### New Feature diff --git a/packages/jest-puppeteer-axe/package.json b/packages/jest-puppeteer-axe/package.json index 03e84e46c75e0b..06f49b3c279edf 100644 --- a/packages/jest-puppeteer-axe/package.json +++ b/packages/jest-puppeteer-axe/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/jest-puppeteer-axe", - "version": "1.6.0", + "version": "1.7.0", "description": "Axe API integration with Jest and Puppeteer.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -30,8 +30,8 @@ "main": "build/index.js", "module": "build-module/index.js", "dependencies": { - "@babel/runtime": "^7.8.3", - "axe-puppeteer": "^1.0.0" + "@babel/runtime": "^7.9.2", + "axe-puppeteer": "^1.1.0" }, "peerDependencies": { "jest": ">=24", diff --git a/packages/keyboard-shortcuts/README.md b/packages/keyboard-shortcuts/README.md index 5bb9f1480a4481..bfb6cd62106fee 100644 --- a/packages/keyboard-shortcuts/README.md +++ b/packages/keyboard-shortcuts/README.md @@ -1,4 +1,4 @@ -# Keycodes +# Keyboard Shortcuts Keyboard shortcuts is a generic package that allow registering andd modifying shortcuts. diff --git a/packages/keyboard-shortcuts/package.json b/packages/keyboard-shortcuts/package.json index 0715071417b459..40bc5926ef228f 100644 --- a/packages/keyboard-shortcuts/package.json +++ b/packages/keyboard-shortcuts/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/keyboard-shortcuts", - "version": "1.1.1", + "version": "1.3.1", "description": "Handling keyboard shortcuts.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -21,7 +21,7 @@ "module": "build-module/index.js", "react-native": "src/index", "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/compose": "file:../compose", "@wordpress/data": "file:../data", "@wordpress/element": "file:../element", diff --git a/packages/keycodes/CHANGELOG.md b/packages/keycodes/CHANGELOG.md index b630cfb0799b3a..ac2aec6c368b01 100644 --- a/packages/keycodes/CHANGELOG.md +++ b/packages/keycodes/CHANGELOG.md @@ -1,3 +1,9 @@ +## Master + +### Bug Fixes + +- `isKeyboardEvent` now tests expected modifiers as an exclusive set, fixing an issue where additional modifiers would wrongly report as satisfying a test for a subset of those modifiers [#20733](https://github.com/WordPress/gutenberg/pull/20733). + ## 2.0.5 (2018-11-21) ## 2.0.4 (2018-11-20) diff --git a/packages/keycodes/README.md b/packages/keycodes/README.md index 7d54480a89b4bd..bb7036ba95de74 100644 --- a/packages/keycodes/README.md +++ b/packages/keycodes/README.md @@ -162,6 +162,10 @@ Keycode for TAB key. Keycode for UP key. +<a name="ZERO" href="#ZERO">#</a> **ZERO** + +Keycode for ZERO key. + <!-- END TOKEN(Autogenerated API docs) --> diff --git a/packages/keycodes/package.json b/packages/keycodes/package.json index 8aae78cf107225..8462ac6515b89c 100644 --- a/packages/keycodes/package.json +++ b/packages/keycodes/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/keycodes", - "version": "2.9.0", + "version": "2.11.0", "description": "Keycodes utilities for WordPress. Used to check for keyboard events across browsers/operating systems.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -22,7 +22,7 @@ "react-native": "src/index", "sideEffects": false, "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/i18n": "file:../i18n", "lodash": "^4.17.15" }, diff --git a/packages/keycodes/src/index.js b/packages/keycodes/src/index.js index 998200bd21f31b..f9de2e6c9d67cf 100644 --- a/packages/keycodes/src/index.js +++ b/packages/keycodes/src/index.js @@ -12,7 +12,7 @@ /** * External dependencies */ -import { get, mapValues, includes, capitalize } from 'lodash'; +import { get, mapValues, includes, capitalize, xor } from 'lodash'; /** * WordPress dependencies @@ -32,7 +32,7 @@ import { isAppleOS } from './platform'; * An object of handler functions for each of the possible modifier * combinations. A handler will return a value for a given key. * - * @typedef {{[M in WPKeycodeModifier]:(key:string)=>any}} WPKeycodeHandlerByModifier + * @typedef {Record<WPKeycodeModifier, (key:string)=>any>} WPKeycodeHandlerByModifier */ /** @@ -95,6 +95,10 @@ export const COMMAND = 'meta'; * Keycode for SHIFT key. */ export const SHIFT = 'shift'; +/** + * Keycode for ZERO key. + */ +export const ZERO = 48; /** * Object that contains functions that return the available modifier @@ -219,6 +223,20 @@ export const shortcutAriaLabel = mapValues( modifiers, ( modifier ) => { }; } ); +/** + * From a given KeyboardEvent, returns an array of active modifier constants for + * the event. + * + * @param {KeyboardEvent} event Keyboard event. + * + * @return {Array<ALT|CTRL|COMMAND|SHIFT>} Active modifier constants. + */ +function getEventModifiers( event ) { + return [ ALT, CTRL, COMMAND, SHIFT ].filter( + ( key ) => event[ `${ key }Key` ] + ); +} + /** * An object that contains functions to check if a keyboard event matches a * predefined shortcut combination. @@ -230,8 +248,9 @@ export const shortcutAriaLabel = mapValues( modifiers, ( modifier ) => { export const isKeyboardEvent = mapValues( modifiers, ( getModifiers ) => { return ( event, character, _isApple = isAppleOS ) => { const mods = getModifiers( _isApple ); + const eventMods = getEventModifiers( event ); - if ( ! mods.every( ( key ) => event[ `${ key }Key` ] ) ) { + if ( xor( mods, eventMods ).length ) { return false; } diff --git a/packages/keycodes/src/test/index.js b/packages/keycodes/src/test/index.js index dccd99884ac2b3..5378101cc42ef0 100644 --- a/packages/keycodes/src/test/index.js +++ b/packages/keycodes/src/test/index.js @@ -296,6 +296,21 @@ describe( 'isKeyboardEvent', () => { return attachNode; } + it( 'returns false for a superset of modifiers', () => { + expect.assertions( 3 ); + const attachNode = attachEventListeners( ( event ) => { + expect( + isKeyboardEvent.primary( event, 'm', isAppleOSFalse ) + ).toBe( false ); + } ); + + keyPress( attachNode, { + ctrlKey: true, + shiftKey: true, + key: 'm', + } ); + } ); + describe( 'primary', () => { it( 'should identify modifier key when Ctrl is pressed', () => { expect.assertions( 3 ); @@ -359,7 +374,11 @@ describe( 'isKeyboardEvent', () => { expect.assertions( 3 ); const attachNode = attachEventListeners( ( event ) => { expect( - isKeyboardEvent.primary( event, undefined, isAppleOSFalse ) + isKeyboardEvent.primaryShift( + event, + undefined, + isAppleOSFalse + ) ).toBe( true ); } ); @@ -374,7 +393,11 @@ describe( 'isKeyboardEvent', () => { expect.assertions( 3 ); const attachNode = attachEventListeners( ( event ) => { expect( - isKeyboardEvent.primary( event, undefined, isAppleOSTrue ) + isKeyboardEvent.primaryShift( + event, + undefined, + isAppleOSTrue + ) ).toBe( true ); } ); @@ -389,7 +412,7 @@ describe( 'isKeyboardEvent', () => { expect.assertions( 3 ); const attachNode = attachEventListeners( ( event ) => { expect( - isKeyboardEvent.primary( event, 'm', isAppleOSFalse ) + isKeyboardEvent.primaryShift( event, 'm', isAppleOSFalse ) ).toBe( true ); } ); @@ -404,7 +427,7 @@ describe( 'isKeyboardEvent', () => { expect.assertions( 3 ); const attachNode = attachEventListeners( ( event ) => { expect( - isKeyboardEvent.primary( event, 'm', isAppleOSTrue ) + isKeyboardEvent.primaryShift( event, 'm', isAppleOSTrue ) ).toBe( true ); } ); @@ -421,7 +444,11 @@ describe( 'isKeyboardEvent', () => { expect.assertions( 3 ); const attachNode = attachEventListeners( ( event ) => { expect( - isKeyboardEvent.primary( event, undefined, isAppleOSFalse ) + isKeyboardEvent.secondary( + event, + undefined, + isAppleOSFalse + ) ).toBe( true ); } ); @@ -437,7 +464,7 @@ describe( 'isKeyboardEvent', () => { expect.assertions( 3 ); const attachNode = attachEventListeners( ( event ) => { expect( - isKeyboardEvent.primary( event, undefined, isAppleOSTrue ) + isKeyboardEvent.secondary( event, undefined, isAppleOSTrue ) ).toBe( true ); } ); @@ -453,7 +480,7 @@ describe( 'isKeyboardEvent', () => { expect.assertions( 3 ); const attachNode = attachEventListeners( ( event ) => { expect( - isKeyboardEvent.primary( event, 'm', isAppleOSFalse ) + isKeyboardEvent.secondary( event, 'm', isAppleOSFalse ) ).toBe( true ); } ); @@ -469,7 +496,7 @@ describe( 'isKeyboardEvent', () => { expect.assertions( 3 ); const attachNode = attachEventListeners( ( event ) => { expect( - isKeyboardEvent.primary( event, 'm', isAppleOSTrue ) + isKeyboardEvent.secondary( event, 'm', isAppleOSTrue ) ).toBe( true ); } ); @@ -483,61 +510,61 @@ describe( 'isKeyboardEvent', () => { } ); describe( 'access', () => { - it( 'should identify modifier key when Alt + Ctrl is pressed', () => { + it( 'should identify modifier key when Shift + Alt is pressed', () => { expect.assertions( 3 ); const attachNode = attachEventListeners( ( event ) => { expect( - isKeyboardEvent.primary( event, undefined, isAppleOSFalse ) + isKeyboardEvent.access( event, undefined, isAppleOSFalse ) ).toBe( true ); } ); keyPress( attachNode, { - ctrlKey: true, + shiftKey: true, altKey: true, - key: 'Ctrl', + key: 'Alt', } ); } ); - it( 'should identify modifier key when βŒ₯⌘ is pressed', () => { + it( 'should identify modifier key when Ctrl + βŒ₯ is pressed', () => { expect.assertions( 3 ); const attachNode = attachEventListeners( ( event ) => { expect( - isKeyboardEvent.primary( event, undefined, isAppleOSTrue ) + isKeyboardEvent.access( event, undefined, isAppleOSTrue ) ).toBe( true ); } ); keyPress( attachNode, { - metaKey: true, + ctrlKey: true, altKey: true, - key: 'Meta', + key: 'Alt', } ); } ); - it( 'should identify modifier key when Ctrl + ALt + M is pressed', () => { + it( 'should identify modifier key when Shift + Alt + M is pressed', () => { expect.assertions( 3 ); const attachNode = attachEventListeners( ( event ) => { expect( - isKeyboardEvent.primary( event, 'm', isAppleOSFalse ) + isKeyboardEvent.access( event, 'm', isAppleOSFalse ) ).toBe( true ); } ); keyPress( attachNode, { - ctrlKey: true, + shiftKey: true, altKey: true, key: 'm', } ); } ); - it( 'should identify modifier key when βŒ₯⌘M is pressed', () => { + it( 'should identify modifier key when Ctrl + βŒ₯M is pressed', () => { expect.assertions( 3 ); const attachNode = attachEventListeners( ( event ) => { expect( - isKeyboardEvent.primary( event, 'm', isAppleOSTrue ) + isKeyboardEvent.access( event, 'm', isAppleOSTrue ) ).toBe( true ); } ); keyPress( attachNode, { - metaKey: true, + ctrlKey: true, altKey: true, key: 'm', } ); diff --git a/packages/list-reusable-blocks/package.json b/packages/list-reusable-blocks/package.json index 11d140c37c0c08..663dd41ec67a52 100644 --- a/packages/list-reusable-blocks/package.json +++ b/packages/list-reusable-blocks/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/list-reusable-blocks", - "version": "1.13.4", + "version": "1.15.1", "description": "Adding Export/Import support to the reusable blocks listing.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -20,7 +20,7 @@ "main": "build/index.js", "module": "build-module/index.js", "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/api-fetch": "file:../api-fetch", "@wordpress/components": "file:../components", "@wordpress/compose": "file:../compose", diff --git a/packages/media-utils/package.json b/packages/media-utils/package.json index ad5b98721a2b20..2ba1a89b4349cf 100644 --- a/packages/media-utils/package.json +++ b/packages/media-utils/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/media-utils", - "version": "1.7.2", + "version": "1.9.1", "description": "WordPress Media Upload Utils.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -22,7 +22,7 @@ "main": "build/index.js", "module": "build-module/index.js", "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/api-fetch": "file:../api-fetch", "@wordpress/blob": "file:../blob", "@wordpress/element": "file:../element", diff --git a/packages/media-utils/src/components/media-upload/index.js b/packages/media-utils/src/components/media-upload/index.js index d955161a57139e..3002864d6a46da 100644 --- a/packages/media-utils/src/components/media-upload/index.js +++ b/packages/media-utils/src/components/media-upload/index.js @@ -11,6 +11,8 @@ import { __ } from '@wordpress/i18n'; const { wp } = window; +const DEFAULT_EMPTY_GALLERY = []; + /** * Prepares the Featured Image toolbars and frames. * @@ -280,8 +282,9 @@ class MediaUpload extends Component { addToGallery = false, allowedTypes, multiple = false, - value = null, + value = DEFAULT_EMPTY_GALLERY, } = this.props; + // If the value did not changed there is no need to rebuild the frame, // we can continue to use the existing one. if ( value === this.lastGalleryValue ) { @@ -298,7 +301,7 @@ class MediaUpload extends Component { if ( addToGallery ) { currentState = 'gallery-library'; } else { - currentState = value ? 'gallery-edit' : 'gallery'; + currentState = value && value.length ? 'gallery-edit' : 'gallery'; } if ( ! this.GalleryDetailsMediaFrame ) { this.GalleryDetailsMediaFrame = getGalleryDetailsMediaFrame(); @@ -313,7 +316,7 @@ class MediaUpload extends Component { state: currentState, multiple, selection, - editing: value ? true : false, + editing: value && value.length ? true : false, } ); wp.media.frame = this.frame; this.initializeListeners(); @@ -417,11 +420,7 @@ class MediaUpload extends Component { } openModal() { - if ( - this.props.gallery && - this.props.value && - this.props.value.length > 0 - ) { + if ( this.props.gallery ) { this.buildAndSetGalleryFrame(); } this.frame.open(); diff --git a/packages/media-utils/src/utils/upload-media.js b/packages/media-utils/src/utils/upload-media.js index fb31af14cf4965..aba998e4e2dd4b 100644 --- a/packages/media-utils/src/utils/upload-media.js +++ b/packages/media-utils/src/utils/upload-media.js @@ -118,9 +118,11 @@ export async function uploadMedia( { const validFiles = []; for ( const mediaFile of files ) { - // verify if user is allowed to upload this mime type + // Verify if user is allowed to upload this mime type. + // Defer to the server when type not detected. if ( allowedMimeTypesForUser && + mediaFile.type && ! isAllowedMimeTypeForUser( mediaFile.type ) ) { triggerError( { @@ -133,8 +135,9 @@ export async function uploadMedia( { continue; } - // Check if the block supports this mime type - if ( ! isAllowedType( mediaFile.type ) ) { + // Check if the block supports this mime type. + // Defer to the server when type not detected. + if ( mediaFile.type && ! isAllowedType( mediaFile.type ) ) { triggerError( { code: 'MIME_TYPE_NOT_SUPPORTED', message: __( 'Sorry, this file type is not supported here.' ), diff --git a/packages/notices/package.json b/packages/notices/package.json index 527fda7be11388..210be709b0f20e 100644 --- a/packages/notices/package.json +++ b/packages/notices/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/notices", - "version": "2.0.1", + "version": "2.2.1", "description": "State management for notices.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -21,7 +21,7 @@ "module": "build-module/index.js", "react-native": "src/index", "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/a11y": "file:../a11y", "@wordpress/data": "file:../data", "lodash": "^4.17.15" diff --git a/packages/npm-package-json-lint-config/CHANGELOG.md b/packages/npm-package-json-lint-config/CHANGELOG.md index 945e31866bbe8e..e129f661dd1925 100644 --- a/packages/npm-package-json-lint-config/CHANGELOG.md +++ b/packages/npm-package-json-lint-config/CHANGELOG.md @@ -1,6 +1,14 @@ +## Master + +## 3.0.0 (2020-04-15) + +### Breaking Change + +- Add `types` to the order of preferred properties. ([#18942](https://github.com/WordPress/gutenberg/pull/18942)) + ## 2.0.0 (2019-06-12) -### Braking Change +### Breaking Change - Added `type` and `react-native` to the order of preferred properties. diff --git a/packages/npm-package-json-lint-config/index.js b/packages/npm-package-json-lint-config/index.js index e8fbd3eebdcec2..831970c59bf3a6 100644 --- a/packages/npm-package-json-lint-config/index.js +++ b/packages/npm-package-json-lint-config/index.js @@ -57,6 +57,7 @@ const defaultConfig = { 'main', 'module', 'react-native', + 'types', 'bin', 'dependencies', 'devDependencies', diff --git a/packages/npm-package-json-lint-config/package.json b/packages/npm-package-json-lint-config/package.json index 891d197e331219..5995f4eabd2fd5 100644 --- a/packages/npm-package-json-lint-config/package.json +++ b/packages/npm-package-json-lint-config/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/npm-package-json-lint-config", - "version": "2.2.0", + "version": "3.0.0", "description": "WordPress npm-package-json-lint shareable configuration.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/nux/package.json b/packages/nux/package.json index c0d85e3e2139eb..d32852bec08e1f 100644 --- a/packages/nux/package.json +++ b/packages/nux/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/nux", - "version": "3.12.4", + "version": "3.14.1", "description": "NUX (New User eXperience) module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -21,7 +21,7 @@ "module": "build-module/index.js", "react-native": "src/index", "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/components": "file:../components", "@wordpress/compose": "file:../compose", "@wordpress/data": "file:../data", diff --git a/packages/plugins/package.json b/packages/plugins/package.json index a8b81108c9d414..c04c28315a696c 100644 --- a/packages/plugins/package.json +++ b/packages/plugins/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/plugins", - "version": "2.12.0", + "version": "2.14.1", "description": "Plugins module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -21,7 +21,7 @@ "module": "build-module/index.js", "react-native": "src/index", "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/compose": "file:../compose", "@wordpress/element": "file:../element", "@wordpress/hooks": "file:../hooks", diff --git a/packages/plugins/src/api/index.js b/packages/plugins/src/api/index.js index 8a3a0c0834c385..61c6e6695304ec 100644 --- a/packages/plugins/src/api/index.js +++ b/packages/plugins/src/api/index.js @@ -41,7 +41,8 @@ const plugins = {}; * unique across all registered plugins. * @param {WPPlugin} settings The settings for this plugin. * - * @example <caption>ES5</caption> + * @example + * <caption>ES5</caption> * ```js * // Using ES5 syntax * var el = wp.element.createElement; @@ -78,7 +79,8 @@ const plugins = {}; * } ); * ``` * - * @example <caption>ESNext</caption> + * @example + * <caption>ESNext</caption> * ```js * // Using ESNext syntax * import { PluginSidebar, PluginSidebarMoreMenuItem } from '@wordpress/edit-post'; @@ -153,7 +155,8 @@ export function registerPlugin( name, settings ) { * * @param {string} name Plugin name. * - * @example <caption>ES5</caption> + * @example + * <caption>ES5</caption> * ```js * // Using ES5 syntax * var unregisterPlugin = wp.plugins.unregisterPlugin; @@ -161,7 +164,8 @@ export function registerPlugin( name, settings ) { * unregisterPlugin( 'plugin-name' ); * ``` * - * @example <caption>ESNext</caption> + * @example + * <caption>ESNext</caption> * ```js * // Using ESNext syntax * const { unregisterPlugin } = wp.plugins; diff --git a/packages/plugins/src/components/plugin-area/index.js b/packages/plugins/src/components/plugin-area/index.js index b60ddbfb875667..445ded2e68d9b2 100644 --- a/packages/plugins/src/components/plugin-area/index.js +++ b/packages/plugins/src/components/plugin-area/index.js @@ -18,7 +18,8 @@ import { getPlugins } from '../../api'; /** * A component that renders all plugin fills in a hidden div. * - * @example <caption>ES5</caption> + * @example + * <caption>ES5</caption> * ```js * // Using ES5 syntax * var el = wp.element.createElement; @@ -34,7 +35,8 @@ import { getPlugins } from '../../api'; * } * ``` * - * @example <caption>ESNext</caption> + * @example + * <caption>ESNext</caption> * ```js * // Using ESNext syntax * const { PluginArea } = wp.plugins; diff --git a/packages/prettier-config/CHANGELOG.md b/packages/prettier-config/CHANGELOG.md index 6d73529eee2190..320942d34efb3a 100644 --- a/packages/prettier-config/CHANGELOG.md +++ b/packages/prettier-config/CHANGELOG.md @@ -1,5 +1,7 @@ ## Master +## 0.1.0 (2020-04-01) + ### Initial Release - The config was extracted from `@wordpress/scripts` package ([#20026](https://github.com/WordPress/gutenberg/pull/20026)). diff --git a/packages/prettier-config/lib/index.js b/packages/prettier-config/lib/index.js index 17308856dce9d9..08854b5775981d 100644 --- a/packages/prettier-config/lib/index.js +++ b/packages/prettier-config/lib/index.js @@ -1,4 +1,18 @@ -module.exports = { +/** @typedef {import('prettier').Options} PrettierOptions */ + +/** + * @typedef WPPrettierOptions + * + * @property {boolean} [parenSpacing=true] Insert spaces inside parentheses. + */ + +// Disable reason: The current JSDoc tooling does not yet understand TypeScript +// union types. + +/* eslint-disable jsdoc/valid-types */ +/** @type {PrettierOptions & WPPrettierOptions} */ +/* eslint-enable jsdoc/valid-types */ +const config = { useTabs: true, tabWidth: 4, printWidth: 80, @@ -10,3 +24,5 @@ module.exports = { semi: true, arrowParens: 'always', }; + +module.exports = config; diff --git a/packages/prettier-config/package.json b/packages/prettier-config/package.json index 681c28ea6110c9..40ebfa22f8709c 100644 --- a/packages/prettier-config/package.json +++ b/packages/prettier-config/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/prettier-config", - "version": "0.0.1", + "version": "0.2.0", "description": "WordPress Prettier shared configuration.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -25,6 +25,7 @@ "lib/index.js" ], "main": "lib/index.js", + "types": "build-types", "publishConfig": { "access": "public" } diff --git a/packages/prettier-config/tsconfig.json b/packages/prettier-config/tsconfig.json new file mode 100644 index 00000000000000..426ab13d0aa8f6 --- /dev/null +++ b/packages/prettier-config/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "lib", + "declarationDir": "build-types" + }, + "include": [ "lib/**/*" ] +} diff --git a/packages/primitives/CHANGELOG.md b/packages/primitives/CHANGELOG.md index e597eb0e1e333d..381269dfcfe7fc 100644 --- a/packages/primitives/CHANGELOG.md +++ b/packages/primitives/CHANGELOG.md @@ -1,3 +1,16 @@ ## Master +## 1.3.1 (2020-04-15) + +### Bug Fix + +- Hide TypeScript type declarations ([#21613](https://github.com/WordPress/gutenberg/pull/21613)) + after they were found to conflict with DefinitelyTyped provided declarations. + +## 1.3.0 (2020-04-15) + +- Include TypeScript type declarations ([#21482](https://github.com/WordPress/gutenberg/pull/21482)) + +## 1.0.0 + Initial release. diff --git a/packages/primitives/_tsconfig.json b/packages/primitives/_tsconfig.json new file mode 100644 index 00000000000000..085d6fa752ab04 --- /dev/null +++ b/packages/primitives/_tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "src", + "declarationDir": "build-types" + }, + "include": [ "src/**/*" ], + "references": [ { "path": "../element" } ] +} diff --git a/packages/primitives/package.json b/packages/primitives/package.json index fe3312fb144d9a..349814a1a10446 100644 --- a/packages/primitives/package.json +++ b/packages/primitives/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/primitives", - "version": "1.1.0", + "version": "1.3.1", "description": "WordPress cross-platform primitives.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -23,7 +23,7 @@ "react-native": "src/index", "sideEffects": false, "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/element": "file:../element", "classnames": "^2.2.5" }, diff --git a/packages/primitives/src/svg/index.js b/packages/primitives/src/svg/index.js index 470ee1af88b86a..38f1c3e1b1ce94 100644 --- a/packages/primitives/src/svg/index.js +++ b/packages/primitives/src/svg/index.js @@ -8,26 +8,91 @@ import classnames from 'classnames'; */ import { createElement } from '@wordpress/element'; +// Disable reason: JSDoc linter doesn't seem to parse the union (`&`) correctly. +/* eslint-disable jsdoc/valid-types */ +/** @typedef {{isPressed?: boolean} & import('react').ComponentPropsWithoutRef<'svg'>} SVGProps */ +/* eslint-enable jsdoc/valid-types */ + +/** + * @param {import('react').ComponentPropsWithoutRef<'circle'>} props + * + * @return {JSX.Element} Circle component + */ export const Circle = ( props ) => createElement( 'circle', props ); + +/** + * @param {import('react').ComponentPropsWithoutRef<'g'>} props + * + * @return {JSX.Element} G component + */ export const G = ( props ) => createElement( 'g', props ); + +/** + * @param {import('react').ComponentPropsWithoutRef<'path'>} props + * + * @return {JSX.Element} Path component + */ export const Path = ( props ) => createElement( 'path', props ); + +/** + * @param {import('react').ComponentPropsWithoutRef<'polygon'>} props + * + * @return {JSX.Element} Polygon component + */ export const Polygon = ( props ) => createElement( 'polygon', props ); + +/** + * @param {import('react').ComponentPropsWithoutRef<'rect'>} props + * + * @return {JSX.Element} Rect component + */ export const Rect = ( props ) => createElement( 'rect', props ); + +/** + * @param {import('react').ComponentPropsWithoutRef<'defs'>} props + * + * @return {JSX.Element} Defs component + */ export const Defs = ( props ) => createElement( 'defs', props ); + +/** + * @param {import('react').ComponentPropsWithoutRef<'radialGradient'>} props + * + * @return {JSX.Element} RadialGradient component + */ export const RadialGradient = ( props ) => createElement( 'radialGradient', props ); + +/** + * @param {import('react').ComponentPropsWithoutRef<'linearGradient'>} props + * + * @return {JSX.Element} LinearGradient component + */ export const LinearGradient = ( props ) => createElement( 'linearGradient', props ); + +/** + * @param {import('react').ComponentPropsWithoutRef<'stop'>} props + * + * @return {JSX.Element} Stop component + */ export const Stop = ( props ) => createElement( 'stop', props ); +/** + * + * @param {SVGProps} props isPressed indicates whether the SVG should appear as pressed. + * Other props will be passed through to svg component. + * + * @return {JSX.Element} Stop component + */ export const SVG = ( { className, isPressed, ...props } ) => { const appliedProps = { ...props, className: classnames( className, { 'is-pressed': isPressed } ) || undefined, role: 'img', - 'aria-hidden': 'true', - focusable: 'false', + 'aria-hidden': true, + focusable: false, }; // Disable reason: We need to have a way to render HTML tag for web. diff --git a/packages/priority-queue/CHANGELOG.md b/packages/priority-queue/CHANGELOG.md index e4a76269c9ca8a..203f7825564a5e 100644 --- a/packages/priority-queue/CHANGELOG.md +++ b/packages/priority-queue/CHANGELOG.md @@ -1,5 +1,11 @@ ## Master +## 1.6.0 (2020-04-15) + +### New feature + +- Include TypeScript type declarations ([#18942](https://github.com/WordPress/gutenberg/pull/18942)) + ## 1.5.0 (2020-02-04) ### Bug Fixes diff --git a/packages/priority-queue/README.md b/packages/priority-queue/README.md index 3b6e43861bd2f8..600a82240cbb8e 100644 --- a/packages/priority-queue/README.md +++ b/packages/priority-queue/README.md @@ -40,7 +40,7 @@ queue.add( ctx2, () => console.log( 'This will be printed second' ) ); _Returns_ -- `WPPriorityQueue`: Queue object with `add` and `flush` methods. +- `WPPriorityQueue`: Queue object with `add`, `flush` and `reset` methods. <!-- END TOKEN(Autogenerated API docs) --> diff --git a/packages/priority-queue/package.json b/packages/priority-queue/package.json index 955bbbd161f18b..86afdc9240c100 100644 --- a/packages/priority-queue/package.json +++ b/packages/priority-queue/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/priority-queue", - "version": "1.5.1", + "version": "1.6.0", "description": "Generic browser priority queue.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -21,9 +21,10 @@ "main": "build/index.js", "module": "build-module/index.js", "react-native": "src/index", + "types": "build-types", "sideEffects": false, "dependencies": { - "@babel/runtime": "^7.8.3" + "@babel/runtime": "^7.9.2" }, "publishConfig": { "access": "public" diff --git a/packages/priority-queue/src/index.js b/packages/priority-queue/src/index.js index e1933cbf11a47a..27f3abf81d09a8 100644 --- a/packages/priority-queue/src/index.js +++ b/packages/priority-queue/src/index.js @@ -27,6 +27,12 @@ import requestIdleCallback from './request-idle-callback'; * @typedef {(element:WPPriorityQueueContext)=>boolean} WPPriorityQueueFlush */ +/** + * Reset the queue. + * + * @typedef {()=>void} WPPriorityQueueReset + */ + /** * Priority queue instance. * @@ -34,6 +40,7 @@ import requestIdleCallback from './request-idle-callback'; * * @property {WPPriorityQueueAdd} add Add callback to queue for context. * @property {WPPriorityQueueFlush} flush Flush queue for context. + * @property {WPPriorityQueueReset} reset Reset queue. */ /** @@ -56,25 +63,25 @@ import requestIdleCallback from './request-idle-callback'; * queue.add( ctx2, () => console.log( 'This will be printed second' ) ); *``` * - * @return {WPPriorityQueue} Queue object with `add` and `flush` methods. + * @return {WPPriorityQueue} Queue object with `add`, `flush` and `reset` methods. */ export const createQueue = () => { /** @type {WPPriorityQueueContext[]} */ - const waitingList = []; + let waitingList = []; /** @type {WeakMap<WPPriorityQueueContext,WPPriorityQueueCallback>} */ - const elementsMap = new WeakMap(); + let elementsMap = new WeakMap(); let isRunning = false; + /* eslint-disable jsdoc/valid-types */ /** * Callback to process as much queue as time permits. * - * @type {IdleRequestCallback & FrameRequestCallback} - * * @param {IdleDeadline|number} deadline Idle callback deadline object, or * animation frame timestamp. */ + /* eslint-enable */ const runWaitingList = ( deadline ) => { const hasTimeRemaining = typeof deadline === 'number' @@ -143,8 +150,20 @@ export const createQueue = () => { return true; }; + /** + * Reset the queue without running the pending callbacks. + * + * @type {WPPriorityQueueReset} + */ + const reset = () => { + waitingList = []; + elementsMap = new WeakMap(); + isRunning = false; + }; + return { add, flush, + reset, }; }; diff --git a/packages/priority-queue/src/request-idle-callback.js b/packages/priority-queue/src/request-idle-callback.js index eee8044fe365e5..64b51e7d2b3364 100644 --- a/packages/priority-queue/src/request-idle-callback.js +++ b/packages/priority-queue/src/request-idle-callback.js @@ -1,5 +1,9 @@ /** - * @return {typeof window.requestIdleCallback|typeof window.requestAnimationFrame|((callback:(timestamp:number)=>void)=>void)} + * @typedef {( timeOrDeadline: IdleDeadline | number ) => void} Callback + */ + +/** + * @return {(callback: Callback) => void} RequestIdleCallback */ export function createRequestIdleCallback() { if ( typeof window === 'undefined' ) { diff --git a/packages/priority-queue/tsconfig.json b/packages/priority-queue/tsconfig.json new file mode 100644 index 00000000000000..3c2c31f506f132 --- /dev/null +++ b/packages/priority-queue/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "src", + "declarationDir": "build-types" + }, + "include": [ "src/**/*" ] +} diff --git a/packages/project-management-automation/CHANGELOG.md b/packages/project-management-automation/CHANGELOG.md index 2c2284ae8eebfc..4a166fb4115d13 100644 --- a/packages/project-management-automation/CHANGELOG.md +++ b/packages/project-management-automation/CHANGELOG.md @@ -1,3 +1,16 @@ +## Master + +## 1.4.0 (2020-04-15) + +### New feature + +- Include TypeScript type declarations ([#18942](https://github.com/WordPress/gutenberg/pull/18942)) +- The "Add First Time Contributor Label" task now prompts the user to link their GitHub account to their WordPress.org profile if neccessary for props credit. The task has been renamed "First Time Contributor". + +### Improvements + +- The "Add First Time Contributor Label" task now runs retroactively on pushes to master, due to [permission constraints](https://help.github.com/en/actions/configuring-and-managing-workflows/authenticating-with-the-github_token#permissions-for-the-github_token) of GitHub Actions. + ## 1.0.0 (2019-08-29) - Initial release. diff --git a/packages/project-management-automation/README.md b/packages/project-management-automation/README.md index 40c85f70a67233..17726771d94e66 100644 --- a/packages/project-management-automation/README.md +++ b/packages/project-management-automation/README.md @@ -2,7 +2,7 @@ This is a [GitHub Action](https://help.github.com/en/categories/automating-your-workflow-with-github-actions) which contains various automation to assist with managing the Gutenberg GitHub repository: -- `add-first-time-contributor-label`: Adds the 'First Time Contributor' label to PRs opened by contributors that have not yet made a commit. +- `first-time-contributor`: Adds the 'First Time Contributor' label to PRs merged on behalf of contributors that have not previously made a contribution, and prompts the user to link their GitHub account to their WordPress.org profile if neccessary for props credit. - `add-milestone`: Assigns the correct milestone to PRs once merged. - `assign-fixed-issues`: Assigns any issues 'fixed' by a newly opened PR to the author of that PR. diff --git a/packages/project-management-automation/lib/add-first-time-contributor-label.js b/packages/project-management-automation/lib/add-first-time-contributor-label.js deleted file mode 100644 index 661a2412b03ac5..00000000000000 --- a/packages/project-management-automation/lib/add-first-time-contributor-label.js +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Internal dependencies - */ -const debug = require( './debug' ); - -/** @typedef {import('@actions/github').GitHub} GitHub */ -/** @typedef {import('@octokit/webhooks').WebhookPayloadPullRequest} WebhookPayloadPullRequest */ - -/** - * Adds the 'First Time Contributor' label to PRs opened by contributors that - * have not yet made a commit. - * - * @param {WebhookPayloadPullRequest} payload Pull request event payload. - * @param {GitHub} octokit Initialized Octokit REST client. - */ -async function addFirstTimeContributorLabel( payload, octokit ) { - const owner = payload.repository.owner.login; - const repo = payload.repository.name; - const author = payload.pull_request.user.login; - - debug( - `add-first-time-contributor-label: Searching for commits in ${ owner }/${ repo } by @${ author }` - ); - - const { - data: { total_count: totalCount }, - } = await octokit.search.commits( { - q: `repo:${ owner }/${ repo }+author:${ author }`, - } ); - - if ( totalCount !== 0 ) { - debug( - `add-first-time-contributor-label: ${ totalCount } commits found. Aborting` - ); - return; - } - - debug( - `add-first-time-contributor-label: Adding 'First Time Contributor' label to issue #${ payload.pull_request.number }` - ); - - await octokit.issues.addLabels( { - owner, - repo, - issue_number: payload.pull_request.number, - labels: [ 'First-time Contributor' ], - } ); -} - -module.exports = addFirstTimeContributorLabel; diff --git a/packages/project-management-automation/lib/add-milestone.js b/packages/project-management-automation/lib/add-milestone.js index e1e8ae39bc99f4..1716a8bea4f024 100644 --- a/packages/project-management-automation/lib/add-milestone.js +++ b/packages/project-management-automation/lib/add-milestone.js @@ -2,6 +2,7 @@ * Internal dependencies */ const debug = require( './debug' ); +const getAssociatedPullRequest = require( './get-associated-pull-request' ); /** @typedef {import('@octokit/rest').HookError} HookError */ /** @typedef {import('@actions/github').GitHub} GitHub */ @@ -45,8 +46,7 @@ async function addMilestone( payload, octokit ) { return; } - const match = payload.commits[ 0 ].message.match( /\(#(\d+)\)$/m ); - const prNumber = match && match[ 1 ]; + const prNumber = getAssociatedPullRequest( payload.commits[ 0 ] ); if ( ! prNumber ) { debug( 'add-milestone: Commit is not a squashed PR. Aborting' ); return; diff --git a/packages/project-management-automation/lib/first-time-contributor.js b/packages/project-management-automation/lib/first-time-contributor.js new file mode 100644 index 00000000000000..901b9df361e04f --- /dev/null +++ b/packages/project-management-automation/lib/first-time-contributor.js @@ -0,0 +1,124 @@ +/** + * Internal dependencies + */ +const debug = require( './debug' ); +const getAssociatedPullRequest = require( './get-associated-pull-request' ); +const hasWordPressProfile = require( './has-wordpress-profile' ); + +/** @typedef {import('@actions/github').GitHub} GitHub */ +/** @typedef {import('@octokit/webhooks').WebhookPayloadPush} WebhookPayloadPush */ +/** @typedef {import('./get-associated-pull-request').WebhookPayloadPushCommit} WebhookPayloadPushCommit */ + +/** + * Returns the message text to be used for the comment prompting contributor to + * link their GitHub account from their WordPress.org profile for props credit. + * + * @param {string} author GitHub username of author. + * + * @return {string} Message text. + */ +function getPromptMessageText( author ) { + return ( + 'Congratulations on your first merged pull request, @' + + author + + "! We'd like to credit you for your contribution in the post " + + "announcing the next WordPress release, but we can't find a " + + 'WordPress.org profile associated with your GitHub account. When you ' + + 'have a moment, visit the following URL and click "link your GitHub ' + + 'account" under "GitHub Username" to link your accounts:\n\n' + + "https://profiles.wordpress.org/me/profile/edit/\n\nAnd if you don't " + + 'have a WordPress.org account, you can create one on this page:\n\n' + + 'https://login.wordpress.org/register\n\nKudos!' + ); +} + +/** + * Adds the 'First Time Contributor' label to PRs merged on behalf of + * contributors that have not yet made a commit, and prompts the user to link + * their GitHub account to their WordPress.org profile if neccessary for props + * credit. + * + * @param {WebhookPayloadPush} payload Push event payload. + * @param {GitHub} octokit Initialized Octokit REST client. + */ +async function firstTimeContributor( payload, octokit ) { + if ( payload.ref !== 'refs/heads/master' ) { + debug( 'first-time-contributor: Commit is not to `master`. Aborting' ); + return; + } + + const commit = + /** @type {WebhookPayloadPushCommit} */ ( payload.commits[ 0 ] ); + const pullRequest = getAssociatedPullRequest( commit ); + if ( ! pullRequest ) { + debug( + 'first-time-contributor: Cannot determine pull request associated with commit. Aborting' + ); + return; + } + + const repo = payload.repository.name; + const owner = payload.repository.owner.login; + const author = commit.author.username; + debug( + `first-time-contributor: Searching for commits in ${ owner }/${ repo } by @${ author }` + ); + + const { data: commits } = await octokit.repos.listCommits( { + owner, + repo, + author, + } ); + + if ( commits.length > 1 ) { + debug( + `first-time-contributor: Not the first commit for author. Aborting` + ); + return; + } + + debug( + `first-time-contributor: Adding 'First Time Contributor' label to issue #${ pullRequest }` + ); + + await octokit.issues.addLabels( { + owner, + repo, + issue_number: pullRequest, + labels: [ 'First-time Contributor' ], + } ); + + debug( + `first-time-contributor: Checking for WordPress username associated with @${ author }` + ); + + let hasProfile; + try { + hasProfile = await hasWordPressProfile( author ); + } catch ( error ) { + debug( + `first-time-contributor: Error retrieving from profile API:\n\n${ error.toString() }` + ); + return; + } + + if ( hasProfile ) { + debug( + `first-time-contributor: User already known. No need to prompt for account link!` + ); + return; + } + + debug( + 'first-time-contributor: User not known. Adding comment to prompt for account link.' + ); + + await octokit.issues.createComment( { + owner, + repo, + issue_number: pullRequest, + body: getPromptMessageText( author ), + } ); +} + +module.exports = firstTimeContributor; diff --git a/packages/project-management-automation/lib/get-associated-pull-request.js b/packages/project-management-automation/lib/get-associated-pull-request.js new file mode 100644 index 00000000000000..6ec267a26a5b8e --- /dev/null +++ b/packages/project-management-automation/lib/get-associated-pull-request.js @@ -0,0 +1,39 @@ +/** + * @typedef WebhookPayloadPushCommitAuthor + * + * @property {string} name Author name. + * @property {string} email Author email. + * @property {string} username Author username. + */ + +/** + * Minimal type detail of GitHub Push webhook event payload, for lack of their + * own. + * + * TODO: If GitHub improves this on their own webhook payload types, this type + * should no longer be necessary. + * + * @typedef {Record<string,*>} WebhookPayloadPushCommit + * + * @property {string} message Commit message. + * @property {WebhookPayloadPushCommitAuthor} author Commit author. + * + * @see https://developer.github.com/v3/activity/events/types/#pushevent + */ + +/** + * Given a commit object, returns a promise resolving with the pull request + * number associated with the commit, or null if an associated pull request + * cannot be determined. + * + * @param {WebhookPayloadPushCommit} commit Commit object. + * + * @return {number?} Pull request number, or null if it cannot be + * determined. + */ +function getAssociatedPullRequest( commit ) { + const match = commit.message.match( /\(#(\d+)\)$/m ); + return match && Number( match[ 1 ] ); +} + +module.exports = getAssociatedPullRequest; diff --git a/packages/project-management-automation/lib/has-wordpress-profile.js b/packages/project-management-automation/lib/has-wordpress-profile.js new file mode 100644 index 00000000000000..cb2adfdba71e0b --- /dev/null +++ b/packages/project-management-automation/lib/has-wordpress-profile.js @@ -0,0 +1,46 @@ +/** + * External dependencies + */ +const { request } = require( 'https' ); + +/** + * Endpoint hostname for WordPress.org profile lookup by GitHub username. + * + * @type {string} + */ +const BASE_PROFILE_LOOKUP_API_HOSTNAME = 'profiles.wordpress.org'; + +/** + * Base path for WordPress.org profile lookup by GitHub username. + * + * @type {string} + */ +const BASE_PROFILE_LOOKUP_API_BASE_PATH = '/wp-json/wporg-github/v1/lookup/'; + +/** + * Returns a promise resolving to a boolean indicating if the given GitHub + * username can be associated with a WordPress.org profile. + * + * @param {string} githubUsername GitHub username. + * + * @return {Promise<boolean>} Promise resolving to whether WordPress profile is + * known. + */ +async function hasWordPressProfile( githubUsername ) { + return new Promise( ( resolve, reject ) => { + const options = { + hostname: BASE_PROFILE_LOOKUP_API_HOSTNAME, + path: BASE_PROFILE_LOOKUP_API_BASE_PATH + githubUsername, + method: 'HEAD', + headers: { + 'User-Agent': 'Gutenberg/project-management-automation', + }, + }; + + request( options, ( res ) => resolve( res.statusCode === 200 ) ) + .on( 'error', ( error ) => reject( error ) ) + .end(); + } ); +} + +module.exports = hasWordPressProfile; diff --git a/packages/project-management-automation/lib/if-not-fork.js b/packages/project-management-automation/lib/if-not-fork.js index 5c8e65adb4d9dd..7ab214026cf8bd 100644 --- a/packages/project-management-automation/lib/if-not-fork.js +++ b/packages/project-management-automation/lib/if-not-fork.js @@ -15,6 +15,7 @@ const debug = require( './debug' ); * @return {WPAutomationTask} Enhanced task. */ function ifNotFork( handler ) { + /** @type {WPAutomationTask} */ const newHandler = ( payload, octokit ) => { if ( payload.pull_request.head.repo.full_name === diff --git a/packages/project-management-automation/lib/index.js b/packages/project-management-automation/lib/index.js index 630bda89440e93..2b280d1d5d5248 100644 --- a/packages/project-management-automation/lib/index.js +++ b/packages/project-management-automation/lib/index.js @@ -8,7 +8,7 @@ const { context, GitHub } = require( '@actions/github' ); * Internal dependencies */ const assignFixedIssues = require( './assign-fixed-issues' ); -const addFirstTimeContributorLabel = require( './add-first-time-contributor-label' ); +const firstTimeContributor = require( './first-time-contributor' ); const addMilestone = require( './add-milestone' ); const debug = require( './debug' ); const ifNotFork = require( './if-not-fork' ); @@ -42,9 +42,8 @@ const automations = [ task: ifNotFork( assignFixedIssues ), }, { - event: 'pull_request', - action: 'opened', - task: ifNotFork( addFirstTimeContributorLabel ), + event: 'push', + task: firstTimeContributor, }, { event: 'push', diff --git a/packages/project-management-automation/lib/test/add-first-time-contributor-label.js b/packages/project-management-automation/lib/test/add-first-time-contributor-label.js deleted file mode 100644 index ac8e5d59f26a0c..00000000000000 --- a/packages/project-management-automation/lib/test/add-first-time-contributor-label.js +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Internal dependencies - */ -import addFirstTimeContributorLabel from '../add-first-time-contributor-label'; - -describe( 'addFirstTimeContributorLabel', () => { - const payload = { - pull_request: { - user: { - login: 'matt', - }, - number: 123, - }, - repository: { - owner: { - login: 'WordPress', - }, - name: 'gutenberg', - }, - }; - - it( 'does nothing if the user has commits', async () => { - const octokit = { - search: { - commits: jest.fn( () => - Promise.resolve( { - data: { - total_count: 100, - }, - } ) - ), - }, - issues: { - addLabels: jest.fn(), - }, - }; - - await addFirstTimeContributorLabel( payload, octokit ); - - expect( octokit.search.commits ).toHaveBeenCalledWith( { - q: 'repo:WordPress/gutenberg+author:matt', - } ); - expect( octokit.issues.addLabels ).not.toHaveBeenCalled(); - } ); - - it( 'adds the label if the user does not have commits', async () => { - const octokit = { - search: { - commits: jest.fn( () => - Promise.resolve( { - data: { - total_count: 0, - }, - } ) - ), - }, - issues: { - addLabels: jest.fn(), - }, - }; - - await addFirstTimeContributorLabel( payload, octokit ); - - expect( octokit.search.commits ).toHaveBeenCalledWith( { - q: 'repo:WordPress/gutenberg+author:matt', - } ); - expect( octokit.issues.addLabels ).toHaveBeenCalledWith( { - owner: 'WordPress', - repo: 'gutenberg', - issue_number: 123, - labels: [ 'First-time Contributor' ], - } ); - } ); -} ); diff --git a/packages/project-management-automation/lib/test/add-milestone.js b/packages/project-management-automation/lib/test/add-milestone.js index 63f49811f9692e..13ecd80aa9b0a2 100644 --- a/packages/project-management-automation/lib/test/add-milestone.js +++ b/packages/project-management-automation/lib/test/add-milestone.js @@ -63,7 +63,7 @@ describe( 'addMilestone', () => { expect( octokit.issues.get ).toHaveBeenCalledWith( { owner: 'WordPress', repo: 'gutenberg', - issue_number: '123', + issue_number: 123, } ); expect( octokit.issues.createMilestone ).not.toHaveBeenCalled(); expect( octokit.issues.listMilestonesForRepo ).not.toHaveBeenCalled(); @@ -124,7 +124,7 @@ describe( 'addMilestone', () => { expect( octokit.issues.get ).toHaveBeenCalledWith( { owner: 'WordPress', repo: 'gutenberg', - issue_number: '123', + issue_number: 123, } ); expect( octokit.repos.getContents ).toHaveBeenCalledWith( { owner: 'WordPress', @@ -144,7 +144,7 @@ describe( 'addMilestone', () => { expect( octokit.issues.update ).toHaveBeenCalledWith( { owner: 'WordPress', repo: 'gutenberg', - issue_number: '123', + issue_number: 123, milestone: 12, } ); } ); @@ -202,7 +202,7 @@ describe( 'addMilestone', () => { expect( octokit.issues.get ).toHaveBeenCalledWith( { owner: 'WordPress', repo: 'gutenberg', - issue_number: '123', + issue_number: 123, } ); expect( octokit.repos.getContents ).toHaveBeenCalledWith( { owner: 'WordPress', @@ -222,7 +222,7 @@ describe( 'addMilestone', () => { expect( octokit.issues.update ).toHaveBeenCalledWith( { owner: 'WordPress', repo: 'gutenberg', - issue_number: '123', + issue_number: 123, milestone: 12, } ); } ); diff --git a/packages/project-management-automation/lib/test/first-time-contributor.js b/packages/project-management-automation/lib/test/first-time-contributor.js new file mode 100644 index 00000000000000..27a328c2b5948e --- /dev/null +++ b/packages/project-management-automation/lib/test/first-time-contributor.js @@ -0,0 +1,216 @@ +/** + * Internal dependencies + */ +import firstTimeContributor from '../first-time-contributor'; +import hasWordPressProfile from '../has-wordpress-profile'; + +jest.mock( '../has-wordpress-profile', () => jest.fn() ); + +describe( 'firstTimeContributor', () => { + beforeEach( () => { + hasWordPressProfile.mockReset(); + } ); + + const payload = { + ref: 'refs/heads/master', + commits: [ + { + id: '4c535288a6a2b75ff23ee96c75f7d9877e919241', + message: 'Add a feature from pull request (#123)', + author: { + name: 'Ghost', + email: 'ghost@example.invalid', + username: 'ghost', + }, + }, + ], + repository: { + owner: { + login: 'WordPress', + }, + name: 'gutenberg', + }, + }; + + it( 'does nothing if not a commit to master', async () => { + const payloadForBranchPush = { + ...payload, + ref: 'refs/heads/update/chicken-branch', + }; + + const octokit = { + repos: { + listCommits: jest.fn(), + }, + }; + + await firstTimeContributor( payloadForBranchPush, octokit ); + + expect( octokit.repos.listCommits ).not.toHaveBeenCalled(); + } ); + + it( 'does nothing if commit pull request undeterminable', async () => { + const payloadDirectToMaster = { + ...payload, + commits: [ + { + message: 'Add a feature direct to master', + author: { + name: 'Ghost', + email: 'ghost@example.invalid', + username: 'ghost', + }, + }, + ], + }; + + const octokit = { + repos: { + listCommits: jest.fn(), + }, + }; + + await firstTimeContributor( payloadDirectToMaster, octokit ); + + expect( octokit.repos.listCommits ).not.toHaveBeenCalled(); + } ); + + it( 'does nothing if the user has multiple commits', async () => { + const octokit = { + repos: { + listCommits: jest.fn( () => + Promise.resolve( { + data: [ + { sha: '4c535288a6a2b75ff23ee96c75f7d9877e919241' }, + { sha: '59b07cc57adff90630fc9d5cf2317269a0f4f158' }, + ], + } ) + ), + }, + issues: { + addLabels: jest.fn(), + }, + }; + + await firstTimeContributor( payload, octokit ); + + expect( octokit.repos.listCommits ).toHaveBeenCalledWith( { + owner: 'WordPress', + repo: 'gutenberg', + author: 'ghost', + } ); + expect( octokit.issues.addLabels ).not.toHaveBeenCalled(); + } ); + + it( 'adds the label if this was the first commit for the user', async () => { + const octokit = { + repos: { + listCommits: jest.fn( () => + Promise.resolve( { + data: [ + { sha: '4c535288a6a2b75ff23ee96c75f7d9877e919241' }, + ], + } ) + ), + }, + issues: { + addLabels: jest.fn(), + createComment: jest.fn(), + }, + }; + + hasWordPressProfile.mockReturnValue( Promise.resolve( true ) ); + + await firstTimeContributor( payload, octokit ); + + expect( octokit.repos.listCommits ).toHaveBeenCalledWith( { + owner: 'WordPress', + repo: 'gutenberg', + author: 'ghost', + } ); + expect( octokit.issues.addLabels ).toHaveBeenCalledWith( { + owner: 'WordPress', + repo: 'gutenberg', + issue_number: 123, + labels: [ 'First-time Contributor' ], + } ); + expect( octokit.issues.createComment ).not.toHaveBeenCalled(); + } ); + + it( 'aborts if the request to retrieve WordPress.org user profile fails', async () => { + const octokit = { + repos: { + listCommits: jest.fn( () => + Promise.resolve( { + data: [ + { sha: '4c535288a6a2b75ff23ee96c75f7d9877e919241' }, + ], + } ) + ), + }, + issues: { + addLabels: jest.fn(), + createComment: jest.fn(), + }, + }; + + hasWordPressProfile.mockImplementation( () => { + return Promise.reject( new Error( 'Whoops!' ) ); + } ); + + await firstTimeContributor( payload, octokit ); + + expect( octokit.repos.listCommits ).toHaveBeenCalledWith( { + owner: 'WordPress', + repo: 'gutenberg', + author: 'ghost', + } ); + expect( octokit.issues.addLabels ).toHaveBeenCalledWith( { + owner: 'WordPress', + repo: 'gutenberg', + issue_number: 123, + labels: [ 'First-time Contributor' ], + } ); + expect( octokit.issues.createComment ).not.toHaveBeenCalled(); + } ); + + it( 'prompts the user to link their GitHub account to their WordPress.org profile', async () => { + const octokit = { + repos: { + listCommits: jest.fn( () => + Promise.resolve( { + data: [ + { sha: '4c535288a6a2b75ff23ee96c75f7d9877e919241' }, + ], + } ) + ), + }, + issues: { + addLabels: jest.fn(), + createComment: jest.fn(), + }, + }; + + hasWordPressProfile.mockReturnValue( Promise.resolve( false ) ); + + await firstTimeContributor( payload, octokit ); + + expect( octokit.repos.listCommits ).toHaveBeenCalledWith( { + owner: 'WordPress', + repo: 'gutenberg', + author: 'ghost', + } ); + expect( octokit.issues.addLabels ).toHaveBeenCalledWith( { + owner: 'WordPress', + repo: 'gutenberg', + issue_number: 123, + labels: [ 'First-time Contributor' ], + } ); + expect( octokit.issues.createComment ).toHaveBeenCalledWith( { + owner: 'WordPress', + repo: 'gutenberg', + issue_number: 123, + body: expect.stringMatching( /^Congratulations/ ), + } ); + } ); +} ); diff --git a/packages/project-management-automation/lib/test/get-associated-pull-request.js b/packages/project-management-automation/lib/test/get-associated-pull-request.js new file mode 100644 index 00000000000000..1e00d636e94e2a --- /dev/null +++ b/packages/project-management-automation/lib/test/get-associated-pull-request.js @@ -0,0 +1,37 @@ +/** + * Internal dependencies + */ +import getAssociatedPullRequest from '../get-associated-pull-request'; + +/** @typedef {import('../get-associated-pull-request').WebhookPayloadPushCommit} WebhookPayloadPushCommit */ + +/** + * An example commit which can be associated with a pull request, e.g. a pull + * request merge commit. + * + * @type {WebhookPayloadPushCommit} + */ +const VALID_COMMIT = { + message: + 'Components: SlotFill: Guard property access to possibly-undefined slot (#21205)', +}; + +/** + * An example commit which cannot be associated with a pull request, e.g. when + * someone commits directly to master. + * + * @type {WebhookPayloadPushCommit} + */ +const INVALID_COMMIT = { + message: 'Add basic placeholder content to post title, content, and date.', +}; + +describe( 'getAssociatedPullRequest', () => { + it( 'should return the pull request number associated with a commit', () => { + expect( getAssociatedPullRequest( VALID_COMMIT ) ).toBe( 21205 ); + } ); + + it( 'should return null if a pull request cannot be determined', () => { + expect( getAssociatedPullRequest( INVALID_COMMIT ) ).toBeNull(); + } ); +} ); diff --git a/packages/project-management-automation/lib/test/has-wordpress-profile.js b/packages/project-management-automation/lib/test/has-wordpress-profile.js new file mode 100644 index 00000000000000..9cb13544a245a1 --- /dev/null +++ b/packages/project-management-automation/lib/test/has-wordpress-profile.js @@ -0,0 +1,31 @@ +/** + * External dependencies + */ +import nock from 'nock'; + +/** + * Internal dependencies + */ +import hasWordPressProfile from '../has-wordpress-profile'; + +describe( 'hasWordPressProfile', () => { + it( 'resolves as false for missing profile', async () => { + nock( 'https://profiles.wordpress.org' ) + .intercept( '/wp-json/wporg-github/v1/lookup/ghost', 'HEAD' ) + .reply( 404 ); + + const result = await hasWordPressProfile( 'ghost' ); + + expect( result ).toBe( false ); + } ); + + it( 'resolves as true for known profile', async () => { + nock( 'https://profiles.wordpress.org' ) + .intercept( '/wp-json/wporg-github/v1/lookup/m', 'HEAD' ) + .reply( 200 ); + + const result = await hasWordPressProfile( 'm' ); + + expect( result ).toBe( true ); + } ); +} ); diff --git a/packages/project-management-automation/package.json b/packages/project-management-automation/package.json index 3e41185ada8c0e..aa62fdfc699e4e 100644 --- a/packages/project-management-automation/package.json +++ b/packages/project-management-automation/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/project-management-automation", - "version": "1.2.0", + "version": "1.4.0", "description": "GitHub Action that implements various automation to assist with managing the Gutenberg GitHub repository.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -17,10 +17,11 @@ "url": "https://github.com/WordPress/gutenberg/issues" }, "main": "lib/index.js", + "types": "build-types", "dependencies": { "@actions/core": "^1.0.0", "@actions/github": "^1.0.0", - "@babel/runtime": "^7.8.3" + "@babel/runtime": "^7.9.2" }, "publishConfig": { "access": "public" diff --git a/packages/project-management-automation/tsconfig.json b/packages/project-management-automation/tsconfig.json new file mode 100644 index 00000000000000..395281ecb0e72d --- /dev/null +++ b/packages/project-management-automation/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "lib", + "declarationDir": "build-types", + + // This is required due to a type error coming from missing types in @actions/github + "noImplicitAny": false + }, + "include": [ "lib/**/*" ] +} diff --git a/packages/react-native-aztec/RNTAztecView.podspec b/packages/react-native-aztec/RNTAztecView.podspec index 3560c7fcfa0269..3bbda789024d1f 100644 --- a/packages/react-native-aztec/RNTAztecView.podspec +++ b/packages/react-native-aztec/RNTAztecView.podspec @@ -18,6 +18,6 @@ Pod::Spec.new do |s| s.xcconfig = {'OTHER_LDFLAGS' => '-lxml2', 'HEADER_SEARCH_PATHS' => '/usr/include/libxml2'} s.dependency 'React-Core' - s.dependency 'WordPress-Aztec-iOS', '1.16.0' + s.dependency 'WordPress-Aztec-iOS', '~> 1.17.1' end diff --git a/packages/react-native-aztec/android/build.gradle b/packages/react-native-aztec/android/build.gradle index f4c94eaa360d2f..26ec5a3a55d3d9 100644 --- a/packages/react-native-aztec/android/build.gradle +++ b/packages/react-native-aztec/android/build.gradle @@ -12,7 +12,7 @@ buildscript { wordpressUtilsVersion = '1.22' espressoVersion = '3.0.1' - aztecVersion = 'v1.3.38' + aztecVersion = 'v1.3.39' } repositories { diff --git a/packages/react-native-bridge/android/build.gradle b/packages/react-native-bridge/android/build.gradle index f2957eb63c3910..ee2e7ceafaf5ca 100644 --- a/packages/react-native-bridge/android/build.gradle +++ b/packages/react-native-bridge/android/build.gradle @@ -133,6 +133,7 @@ dependencies { implementation project(':react-native-svg') implementation project(':react-native-video') implementation project(':@react-native-community_slider') + implementation project(':react-native-get-random-values') implementation 'com.facebook.react:react-native:+' } else { @@ -142,6 +143,7 @@ dependencies { implementation (waitJitpack('com.github.wordpress-mobile', 'react-native-video', readHashedVersion('../../package.json', 'react-native-video', 'dependencies'))) implementation (waitJitpack('com.github.wordpress-mobile', 'react-native-linear-gradient', readHashedVersion('../../package.json', 'react-native-linear-gradient', 'dependencies'))) implementation (waitJitpack('com.github.wordpress-mobile', 'react-native-slider', readHashedVersion('../../package.json', '@react-native-community/slider', 'dependencies'))) + implementation (waitJitpack('com.github.wordpress-mobile', 'react-native-get-random-values', readHashedVersion('../../package.json', 'react-native-get-random-values', 'dependencies'))) // FIXME Temporary fix to get Jitpack builds to green while I work on a solution without hardcoded values. //def rnVersion = readReactNativeVersion('../package.json', 'peerDependencies') @@ -161,7 +163,7 @@ if (isJitPack) { args = ['bundle:android'] } - task ensureAssetsDirectory { + task ensureAssetsDirectory { doLast { mkdir assetsFolder } diff --git a/packages/react-native-bridge/android/settings.gradle b/packages/react-native-bridge/android/settings.gradle index 5f5c7bb9f2330d..004f79b37fcb5d 100644 --- a/packages/react-native-bridge/android/settings.gradle +++ b/packages/react-native-bridge/android/settings.gradle @@ -2,3 +2,4 @@ rootProject.name = '@wordpress/react-native-bridge' include ':@wordpress_react-native-aztec' project(':@wordpress_react-native-aztec').projectDir = new File(rootProject.projectDir, '../../react-native-aztec/android') + diff --git a/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergBridgeJS2Parent.java b/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergBridgeJS2Parent.java index a9cde47618d840..fabc124efd2bce 100644 --- a/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergBridgeJS2Parent.java +++ b/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergBridgeJS2Parent.java @@ -17,6 +17,7 @@ interface RNMedia { String getUrl(); int getId(); String getType(); + String getCaption(); WritableMap toMap(); } diff --git a/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/RNReactNativeGutenbergBridgeModule.java b/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/RNReactNativeGutenbergBridgeModule.java index 3d019ceead1c51..226b01b6f62f82 100644 --- a/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/RNReactNativeGutenbergBridgeModule.java +++ b/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/RNReactNativeGutenbergBridgeModule.java @@ -37,6 +37,8 @@ public class RNReactNativeGutenbergBridgeModule extends ReactContextBaseJavaModu private static final String EVENT_NAME_FOCUS_TITLE = "setFocusOnTitle"; private static final String EVENT_NAME_MEDIA_UPLOAD = "mediaUpload"; private static final String EVENT_NAME_MEDIA_APPEND = "mediaAppend"; + private static final String EVENT_NAME_TOGGLE_HTML_MODE = "toggleHTMLMode"; + private static final String EVENT_NAME_NOTIFY_MODAL_CLOSED = "notifyModalClosed"; private static final String EVENT_NAME_PREFERRED_COLOR_SCHEME = "preferredColorScheme"; private static final String MAP_KEY_UPDATE_HTML = "html"; @@ -306,6 +308,10 @@ private void setMediaFileUploadDataInJS(int state, int mediaId, String mediaUrl, } public void toggleEditorMode() { - emitToJS("toggleHTMLMode", null); + emitToJS(EVENT_NAME_TOGGLE_HTML_MODE, null); + } + + public void notifyModalClosed() { + emitToJS(EVENT_NAME_NOTIFY_MODAL_CLOSED, null); } } diff --git a/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/Media.java b/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/Media.java index 1e754891297b42..d403eb0c977070 100644 --- a/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/Media.java +++ b/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/Media.java @@ -13,20 +13,23 @@ public class Media implements RNMedia { private int mId; private String mUrl; private String mType; + private String mCaption; - public Media(int id, String url, String type) { + public Media(int id, String url, String type, String caption) { this.mId = id; this.mUrl = url; this.mType = type; + this.mCaption = caption; } public Media(int id, String url) { this.mId = id; this.mUrl = url; this.mType = ""; + this.mCaption = ""; } - public static Media createRNMediaUsingMimeType(final int id, final String url, @NonNull final String mimeType) { + public static Media createRNMediaUsingMimeType(final int id, final String url, @NonNull final String mimeType, final String caption) { String type; if (mimeType.startsWith(MediaType.IMAGE.name().toLowerCase(Locale.ROOT))) { @@ -37,7 +40,7 @@ public static Media createRNMediaUsingMimeType(final int id, final String url, @ type = MediaType.OTHER.name().toLowerCase(Locale.ROOT); } - return new Media(id, url, type); + return new Media(id, url, type, caption); } @@ -65,11 +68,20 @@ public void setType(String mediaType) { this.mType = mediaType; } + public String getCaption() { + return mCaption; + } + + public void setCaption(String caption) { + this.mCaption = caption; + } + public WritableMap toMap() { WritableMap map = new WritableNativeMap(); map.putInt("id", mId); map.putString("url", mUrl); map.putString("type", mType); + map.putString("caption", mCaption); return map; } } diff --git a/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/OkHttpHeaderInterceptor.java b/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/OkHttpHeaderInterceptor.java index 3e285f6e19c4b0..16b8b734ef895b 100644 --- a/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/OkHttpHeaderInterceptor.java +++ b/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/OkHttpHeaderInterceptor.java @@ -1,18 +1,15 @@ package org.wordpress.mobile.WPAndroidGlue; -import android.text.TextUtils; - import org.wordpress.mobile.WPAndroidGlue.WPAndroidGlueCode.OnAuthHeaderRequestedListener; import java.io.IOException; +import java.util.Map; import okhttp3.Interceptor; import okhttp3.Request; import okhttp3.Response; public class OkHttpHeaderInterceptor implements Interceptor { - private static final String AUTHORIZATION_HEADER_KEY = "Authorization"; - private OnAuthHeaderRequestedListener mOnAuthHeaderRequestedListener; void setOnAuthHeaderRequestedListener(OnAuthHeaderRequestedListener onAuthHeaderRequestedListener) { @@ -23,10 +20,13 @@ void setOnAuthHeaderRequestedListener(OnAuthHeaderRequestedListener onAuthHeader public Response intercept(Chain chain) throws IOException { Request.Builder builder = chain.request().newBuilder(); - String authHeader = mOnAuthHeaderRequestedListener != null + Map<String, String> authHeaders = mOnAuthHeaderRequestedListener != null ? mOnAuthHeaderRequestedListener.onAuthHeaderRequested(chain.request().url().toString()) : null; - if (!TextUtils.isEmpty(authHeader)) { - builder.addHeader(AUTHORIZATION_HEADER_KEY, authHeader); + + if (authHeaders != null) { + for (Map.Entry<String, String> entry : authHeaders.entrySet()) { + builder.addHeader(entry.getKey(), entry.getValue()); + } } return chain.proceed(builder.build()); diff --git a/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/WPAndroidGlueCode.java b/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/WPAndroidGlueCode.java index b9072ca09e6c75..b8836cc7a7615d 100644 --- a/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/WPAndroidGlueCode.java +++ b/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/WPAndroidGlueCode.java @@ -147,7 +147,7 @@ public interface OnEditorMountListener { } public interface OnAuthHeaderRequestedListener { - String onAuthHeaderRequested(String url); + Map<String, String> onAuthHeaderRequested(String url); } public interface OnEditorAutosaveListener { @@ -477,6 +477,11 @@ public void invokeDefaultOnBackPressed() { } } + public void onDetach(Activity activity) { + mReactInstanceManager.onHostDestroy(activity); + mRnReactNativeGutenbergBridgePackage.getRNReactNativeGutenbergBridgeModule().notifyModalClosed(); + } + public void onDestroy(Activity activity) { if (mReactRootView != null) { mReactRootView.unmountReactApplication(); @@ -667,7 +672,7 @@ public void appendUploadMediaFiles(ArrayList<Media> mediaList) { for (Media mediaToAppend : mediaList.subList(1, mediaList.size())) { sendOrDeferAppendMediaSignal(mediaToAppend.getId(), mediaToAppend.getUrl(), - mediaToAppend.getType()); + mediaToAppend.getType(), mediaToAppend.getCaption()); } } else { rnMediaList.addAll(mediaList); @@ -677,14 +682,14 @@ public void appendUploadMediaFiles(ArrayList<Media> mediaList) { // This case is for media that is shared from the device for (Media mediaToAppend : mediaList) { sendOrDeferAppendMediaSignal(mediaToAppend.getId(), mediaToAppend.getUrl(), - mediaToAppend.getType()); + mediaToAppend.getType(), mediaToAppend.getCaption()); } } mAppendsMultipleSelectedToSiblingBlocks = false; } - private void sendOrDeferAppendMediaSignal(final int mediaId, final String mediaUri, final String mediaType) { + private void sendOrDeferAppendMediaSignal(final int mediaId, final String mediaUri, final String mediaType, final String caption) { // if editor is mounted, let's append the media file if (mIsEditorMounted) { if (!TextUtils.isEmpty(mediaUri) && mediaId > 0) { @@ -694,7 +699,7 @@ private void sendOrDeferAppendMediaSignal(final int mediaId, final String mediaU } else { // save the URL, we'll add it once Editor is mounted synchronized (WPAndroidGlueCode.this) { - mMediaToAddAfterMounting.put(mediaId, new Media(mediaId, mediaUri, mediaType)); + mMediaToAddAfterMounting.put(mediaId, new Media(mediaId, mediaUri, mediaType, caption)); } } } diff --git a/packages/react-native-bridge/index.js b/packages/react-native-bridge/index.js index 9ff5adba277bf7..c33a233964c777 100644 --- a/packages/react-native-bridge/index.js +++ b/packages/react-native-bridge/index.js @@ -5,6 +5,7 @@ import { NativeModules, NativeEventEmitter, Platform } from 'react-native'; const { RNReactNativeGutenbergBridge } = NativeModules; const isIOS = Platform.OS === 'ios'; +const isAndroid = Platform.OS === 'android'; const gutenbergBridgeEvents = new NativeEventEmitter( RNReactNativeGutenbergBridge @@ -23,8 +24,6 @@ export const userEvents = { editorSessionTemplatePreview: 'editor_session_template_preview', }; -export const showMediaEditorButton = isIOS; - // Console polyfill from react-native export function nativeLoggingHook( message, logLevel ) { @@ -72,6 +71,12 @@ export function subscribeMediaAppend( callback ) { return gutenbergBridgeEvents.addListener( 'mediaAppend', callback ); } +export function subscribeAndroidModalClosed( callback ) { + return isAndroid + ? gutenbergBridgeEvents.addListener( 'notifyModalClosed', callback ) + : undefined; +} + export function subscribePreferredColorScheme( callback ) { return gutenbergBridgeEvents.addListener( 'preferredColorScheme', diff --git a/packages/react-native-bridge/ios/GutenbergBridgeDelegate.swift b/packages/react-native-bridge/ios/GutenbergBridgeDelegate.swift index 61d607d7ae7652..5e10b9c3779d6b 100644 --- a/packages/react-native-bridge/ios/GutenbergBridgeDelegate.swift +++ b/packages/react-native-bridge/ios/GutenbergBridgeDelegate.swift @@ -2,11 +2,13 @@ public struct MediaInfo { public let id: Int32? public let url: String? public let type: String? + public let caption: String? - public init(id: Int32?, url: String?, type: String?) { + public init(id: Int32?, url: String?, type: String?, caption: String? = nil) { self.id = id self.url = url self.type = type + self.caption = caption } } diff --git a/packages/react-native-bridge/ios/RNReactNativeGutenbergBridge.swift b/packages/react-native-bridge/ios/RNReactNativeGutenbergBridge.swift index b13ca925327675..8d2b26849b2572 100644 --- a/packages/react-native-bridge/ios/RNReactNativeGutenbergBridge.swift +++ b/packages/react-native-bridge/ios/RNReactNativeGutenbergBridge.swift @@ -282,10 +282,11 @@ extension RNReactNativeGutenbergBridge { } extension RNReactNativeGutenbergBridge { - enum mediaDictKeys { - static let IDKey = "id" - static let URLKey = "url" - static let TypeKey = "type" + enum MediaKey { + static let id = "id" + static let url = "url" + static let type = "type" + static let caption = "caption" } } @@ -293,9 +294,10 @@ extension MediaInfo { func encodeForJS() -> [String: Any] { return [ - RNReactNativeGutenbergBridge.mediaDictKeys.IDKey: id as Any, - RNReactNativeGutenbergBridge.mediaDictKeys.URLKey: url as Any, - RNReactNativeGutenbergBridge.mediaDictKeys.TypeKey: type as Any + RNReactNativeGutenbergBridge.MediaKey.id: id as Any, + RNReactNativeGutenbergBridge.MediaKey.url: url as Any, + RNReactNativeGutenbergBridge.MediaKey.type: type as Any, + RNReactNativeGutenbergBridge.MediaKey.caption: caption as Any ] } } diff --git a/packages/react-native-editor/.eslintrc.js b/packages/react-native-editor/.eslintrc.js index eb6abac671c30a..d9065a02370921 100644 --- a/packages/react-native-editor/.eslintrc.js +++ b/packages/react-native-editor/.eslintrc.js @@ -7,7 +7,7 @@ module.exports = { globals: { __DEV__: true, }, - plugins: [ 'react', 'react-native', 'jest' ], + plugins: [ 'react', 'jest' ], extends: [ 'plugin:@wordpress/eslint-plugin/recommended' ], settings: { react: { diff --git a/packages/react-native-editor/.github/PULL_REQUEST_TEMPLATE/release_pull_request.md b/packages/react-native-editor/.github/PULL_REQUEST_TEMPLATE/release_pull_request.md new file mode 100644 index 00000000000000..e5d28f2d19d2a3 --- /dev/null +++ b/packages/react-native-editor/.github/PULL_REQUEST_TEMPLATE/release_pull_request.md @@ -0,0 +1,38 @@ +Release for Gutenberg Mobile v1.XX.Y + +## Related PRs + +- Gutenberg: https://github.com/WordPress/gutenberg/pull/ +- WPAndroid: https://github.com/wordpress-mobile/WordPress-Android/pull/ +- WPiOS: https://github.com/wordpress-mobile/WordPress-iOS/pull/ + +- Aztec-iOS: https://github.com/wordpress-mobile/AztecEditor-iOS/pull/ +- Aztec-Android: https://github.com/wordpress-mobile/AztecEditor-Android/pull + +## Extra PRs that Landed After the Release Was Cut + +- [ ] PR 1 +- [ ] PR 2 + +## Changes +<!-- To determine the changes you can check the RELEASE-NOTES.txt file and cross check with the list of commits that are part of the PR --> + + - Change 1 + - Change 2 + +## Test plan + +- Use the main WP apps to test the changes above. +- Check WPAndroid and WPiOS PRs if there are specific tests to run. +- Smoke test the main WP apps for [general writing flow](https://github.com/wordpress-mobile/test-cases/tree/master/test-cases/gutenberg/writing-flow). + +## Release Submission Checklist + +- [ ] Release number was bumped +- [ ] Aztec dependencies are pointing to a stable release + - iOS: 'grep WordPressAztec-iOS RNTAztecView.podspec' + - Android: 'grep aztecVersion react-native-aztec/android/build.gradle' +- [ ] Gutenberg 'Podfile' and 'Podfile.lock' inside './ios/' are updated to the release number +- [ ] Bundle package of the release is updated +- [ ] Check if `RELEASE-NOTES.txt` is updated with all the changes that made it to the release + diff --git a/packages/react-native-editor/RELEASE-NOTES.txt b/packages/react-native-editor/RELEASE-NOTES.txt index e3459044f05c35..fcdcefa3fc9d68 100644 --- a/packages/react-native-editor/RELEASE-NOTES.txt +++ b/packages/react-native-editor/RELEASE-NOTES.txt @@ -1,6 +1,31 @@ +1.27.0 +------ +* Prefill caption for image blocks when available on the Media library +* New block: Buttons. From now you’ll be able to add the individual Button block only inside the Buttons block +* [iOS]: Video in video blocks can now be played inline on the editor. +* [Android] Floating toolbar, previously located above nested blocks, is now placed at the top of the screen +* [iOS] Floating toolbar, previously located above nested blocks, is now placed at the bottom of the screen +* Fix the icons in FloatingToolbar on RTL mode + +1.26.0 +------ +* [iOS] Disable ripple effect in all BottomSheet's controls. +* [Android] Disable ripple effect for Slider control +* New block: Columns +* New starter page template: Blog +* Make Starter Page Template picker buttons visible only when the screen height is enough +* Fix a bug which caused to show URL settings modal randomly when changing the device orientation multiple times during the time Starter Page Template Preview is open + 1.25.0 ------ -* Improve icon on the "Take a Video" media option +* New block: Cover +* [Android] Dark Mode +* [Android] Improve icon on the "Take a Video" media option +* Removed the dimming effect on unselected blocks +* [iOS] Add alignment options for heading block +* Implemented dropdown toolbar for alignment toolbar in Heading, Paragraph, Image, MediaText blocks +* Block Editor: When editing link settings, tapping the keyboard return button now closes the settings panel as well as closing the keyboard. +* [Android] Show an "Edit" button overlay on selected image blocks 1.24.0 ------ @@ -8,7 +33,6 @@ * Fix Quote block's left border not being visible in Dark Mode * Added Starter Page Templates: when you create a new page, we now show you a few templates to get started more quickly. * Fix crash when pasting HTML content with embeded images on paragraphs -* [Android] Dark Mode 1.23.0 ------ diff --git a/packages/react-native-editor/__device-tests__/gutenberg-editor-heading.test.js b/packages/react-native-editor/__device-tests__/gutenberg-editor-heading.test.js index 65d4dfc2c3f3bf..a20d1aa654ed7c 100644 --- a/packages/react-native-editor/__device-tests__/gutenberg-editor-heading.test.js +++ b/packages/react-native-editor/__device-tests__/gutenberg-editor-heading.test.js @@ -48,7 +48,8 @@ describe( 'Gutenberg Editor tests', () => { } await editorPage.sendTextToHeadingBlock( headingBlockElement, - testData.heading + testData.heading, + false ); await editorPage.addNewParagraphBlock(); @@ -73,7 +74,8 @@ describe( 'Gutenberg Editor tests', () => { headingBlockElement = await editorPage.getHeadingBlockAtPosition( 4 ); await editorPage.sendTextToHeadingBlock( headingBlockElement, - testData.heading + testData.heading, + false ); await editorPage.addNewParagraphBlock(); diff --git a/packages/react-native-editor/__device-tests__/gutenberg-editor-image.test.js b/packages/react-native-editor/__device-tests__/gutenberg-editor-image.test.js index 7f146f6505d88c..2357e506a222c0 100644 --- a/packages/react-native-editor/__device-tests__/gutenberg-editor-image.test.js +++ b/packages/react-native-editor/__device-tests__/gutenberg-editor-image.test.js @@ -58,7 +58,8 @@ describe( 'Gutenberg Editor Image Block tests', () => { await imageBlock.click(); await swipeUp( driver, imageBlock ); await editorPage.enterCaptionToSelectedImageBlock( - testData.imageCaption + testData.imageCaption, + true ); await editorPage.dismissKeyboard(); imageBlock = await editorPage.getImageBlockAtPosition( 1 ); diff --git a/packages/react-native-editor/__device-tests__/gutenberg-editor-latest-posts.test.js b/packages/react-native-editor/__device-tests__/gutenberg-editor-latest-posts.test.js new file mode 100644 index 00000000000000..8093f64d5ba650 --- /dev/null +++ b/packages/react-native-editor/__device-tests__/gutenberg-editor-latest-posts.test.js @@ -0,0 +1,50 @@ +/** + * Internal dependencies + */ +import EditorPage from './pages/editor-page'; +import { setupDriver, isLocalEnvironment, stopDriver } from './helpers/utils'; + +jest.setTimeout( 1000000 ); + +describe( 'Gutenberg Editor Latest Post Block tests', () => { + let driver; + let editorPage; + let allPassed = true; + + // Use reporter for setting status for saucelabs Job + if ( ! isLocalEnvironment() ) { + const reporter = { + specDone: async ( result ) => { + allPassed = allPassed && result.status !== 'failed'; + }, + }; + + jasmine.getEnv().addReporter( reporter ); + } + + beforeAll( async () => { + driver = await setupDriver(); + editorPage = new EditorPage( driver ); + } ); + + it( 'should be able to see visual editor', async () => { + await expect( editorPage.getBlockList() ).resolves.toBe( true ); + } ); + + it( 'should be able to add a Latests-Posts block', async () => { + await editorPage.addNewLatestPostsBlock(); + const latestPostsBlock = await editorPage.getLatestPostsBlockAtPosition( + 1 + ); + + expect( latestPostsBlock ).toBeTruthy(); + await editorPage.removeLatestPostsBlockAtPosition( 1 ); + } ); + + afterAll( async () => { + if ( ! isLocalEnvironment() ) { + driver.sauceJobStatus( allPassed ); + } + await stopDriver( driver ); + } ); +} ); diff --git a/packages/react-native-editor/__device-tests__/helpers/appium-local.js b/packages/react-native-editor/__device-tests__/helpers/appium-local.js index 48c6e97f1185fd..71a0cd44aea18b 100644 --- a/packages/react-native-editor/__device-tests__/helpers/appium-local.js +++ b/packages/react-native-editor/__device-tests__/helpers/appium-local.js @@ -5,7 +5,7 @@ import childProcess from 'child_process'; // Spawns an appium process export const start = ( localAppiumPort ) => - new Promise()( ( resolve, reject ) => { + new Promise( ( resolve, reject ) => { const appium = childProcess.spawn( 'appium', [ '--port', localAppiumPort.toString(), diff --git a/packages/react-native-editor/__device-tests__/helpers/caps.js b/packages/react-native-editor/__device-tests__/helpers/caps.js index ea0c7559675678..d9b32b936b7517 100644 --- a/packages/react-native-editor/__device-tests__/helpers/caps.js +++ b/packages/react-native-editor/__device-tests__/helpers/caps.js @@ -15,7 +15,7 @@ const ios = { exports.iosLocal = { ...ios, - platformVersion: '13.3', + platformVersion: '13.4', deviceName: 'iPhone 11', }; diff --git a/packages/react-native-editor/__device-tests__/helpers/utils.js b/packages/react-native-editor/__device-tests__/helpers/utils.js index 3624504685af7e..2b55b11d9187b0 100644 --- a/packages/react-native-editor/__device-tests__/helpers/utils.js +++ b/packages/react-native-editor/__device-tests__/helpers/utils.js @@ -43,7 +43,7 @@ const strToKeycode = { '\u0008': 67, }; -const timer = ( ms ) => new Promise()( ( res ) => setTimeout( res, ms ) ); +const timer = ( ms ) => new Promise( ( res ) => setTimeout( res, ms ) ); const isAndroid = () => { return rnPlatform.toLowerCase() === 'android'; @@ -167,11 +167,28 @@ const typeString = async ( driver, element, str, clear ) => { const typeStringIos = async ( driver, element, str, clear ) => { if ( clear ) { - await element.clear(); + //await element.clear(); This was not working correctly on iOS so need a custom implementation + await clearTextBox( driver, element ); } await element.type( str ); }; +const clearTextBox = async ( driver, element ) => { + await element.click(); + let originalText = await element.text(); + let text = originalText; + // We are double tapping on the text field and pressing backspace until all content is removed. + do { + originalText = await element.text(); + const action = new wd.TouchAction( driver ); + action.tap( { el: element, count: 2 } ); + await action.perform(); + await element.type( '\b' ); + text = await element.text(); + // We compare with the original content and not empty because text always return any hint set on the element. + } while ( originalText !== text ); +}; + const typeStringAndroid = async ( driver, element, diff --git a/packages/react-native-editor/__device-tests__/pages/editor-page.js b/packages/react-native-editor/__device-tests__/pages/editor-page.js index fddb824dff33bf..8136367310bf81 100644 --- a/packages/react-native-editor/__device-tests__/pages/editor-page.js +++ b/packages/react-native-editor/__device-tests__/pages/editor-page.js @@ -10,11 +10,15 @@ import { } from '../helpers/utils'; export default class EditorPage { + driver; + accessibilityIdKey; + accessibilityIdXPathAttrib; paragraphBlockName = 'Paragraph'; listBlockName = 'List'; headingBlockName = 'Heading'; imageBlockName = 'Image'; galleryBlockName = 'Gallery'; + latestPostsBlockName = 'Latest Posts'; unorderedListButtonName = 'Convert to unordered list'; orderedListButtonName = 'Convert to ordered list'; @@ -179,10 +183,48 @@ export default class EditorPage { await addButton.click(); // Click on block of choice + const blockButton = await this.findBlockButton( blockName ); + if ( isAndroid() ) { + await blockButton.click(); + } else { + await this.driver.execute( 'mobile: tap', { + element: blockButton, + x: 10, + y: 10, + } ); + } + } + + // Attempts to find the given block button in the block inserter control. + async findBlockButton( blockName ) { + if ( isAndroid() ) { + // Checks if the Block Button is available, and if not will scroll to the second half of the available buttons. + while ( + ! ( await this.driver.hasElementByAccessibilityId( blockName ) ) + ) { + await this.driver.pressKeycode( 20 ); // Press the Down arrow to force a scroll. + } + + return await this.driver.elementByAccessibilityId( blockName ); + } + const blockButton = await this.driver.elementByAccessibilityId( blockName ); - await blockButton.click(); + const size = await this.driver.getWindowSize(); + const height = size.height - 5; + + while ( ! ( await blockButton.isDisplayed() ) ) { + await this.driver.execute( 'mobile: dragFromToForDuration', { + fromX: 50, + fromY: height, + toX: 50, + toY: height - 450, + duration: 0.5, + } ); + } + + return blockButton; } async clickToolBarButton( buttonName ) { @@ -440,7 +482,7 @@ export default class EditorPage { async enterCaptionToSelectedImageBlock( caption, clear = true ) { const imageBlockCaptionField = await this.driver.elementByXPath( - '//XCUIElementTypeButton[@name="Image caption. Empty"]' + '//XCUIElementTypeButton[starts-with(@name, "Image caption.")]' ); await imageBlockCaptionField.click(); await typeString( this.driver, imageBlockCaptionField, caption, clear ); @@ -515,4 +557,23 @@ export default class EditorPage { const text = await textViewElement.text(); return text.toString(); } + + // ============================ + // Latest-Posts Block functions + // ============================ + + async addNewLatestPostsBlock() { + await this.addNewBlock( this.latestPostsBlockName ); + } + + async getLatestPostsBlockAtPosition( position ) { + return this.getBlockAtPosition( position, this.latestPostsBlockName ); + } + + async removeLatestPostsBlockAtPosition( position ) { + return await this.removeBlockAtPosition( + position, + this.latestPostsBlockName + ); + } } diff --git a/packages/react-native-editor/android/app/build.gradle b/packages/react-native-editor/android/app/build.gradle index dea4ed2f4f185f..865a518fd5c100 100644 --- a/packages/react-native-editor/android/app/build.gradle +++ b/packages/react-native-editor/android/app/build.gradle @@ -161,6 +161,7 @@ dependencies { implementation project(':@react-native-community_slider') implementation project(':react-native-video') implementation project(':react-native-svg') + implementation project(':react-native-get-random-values') implementation "org.wordpress:utils:$wordpressUtilsVersion" implementation 'androidx.appcompat:appcompat:1.0.0' implementation "com.facebook.react:react-native:+" // From node_modules diff --git a/packages/react-native-editor/android/app/src/main/java/com/gutenberg/MainApplication.java b/packages/react-native-editor/android/app/src/main/java/com/gutenberg/MainApplication.java index f610d0eed34506..4967db60826a31 100644 --- a/packages/react-native-editor/android/app/src/main/java/com/gutenberg/MainApplication.java +++ b/packages/react-native-editor/android/app/src/main/java/com/gutenberg/MainApplication.java @@ -16,6 +16,7 @@ import com.facebook.react.devsupport.interfaces.DevOptionHandler; import com.facebook.react.devsupport.interfaces.DevSupportManager; import com.horcrux.svg.SvgPackage; +import org.linusu.RNGetRandomValuesPackage; import org.wordpress.mobile.ReactNativeAztec.ReactAztecPackage; import org.wordpress.mobile.ReactNativeGutenbergBridge.GutenbergBridgeJS2Parent; @@ -28,6 +29,7 @@ import java.util.Arrays; import java.util.List; +import java.util.ArrayList; public class MainApplication extends Application implements ReactApplication { @@ -56,6 +58,13 @@ public void requestMediaPickFromDeviceLibrary(MediaUploadCallback mediaUploadCal @Override public void requestMediaPickFromMediaLibrary(MediaUploadCallback mediaUploadCallback, Boolean allowMultipleSelection, MediaType mediaType) { + List<RNMedia> rnMediaList = new ArrayList<>(); + if (mediaType == MediaType.IMAGE) { + rnMediaList.add(new Media(1, "https://cldup.com/cXyG__fTLN.jpg", "image", "Mountain" )); + } else if (mediaType == MediaType.VIDEO) { + rnMediaList.add(new Media(2, "https://i.cloudup.com/YtZFJbuQCE.mov", "video", "Cloudup" )); + } + mediaUploadCallback.onUploadMediaFileSelected(rnMediaList); } @@ -145,6 +154,7 @@ protected List<ReactPackage> getPackages() { new SvgPackage(), new ReactAztecPackage(), new LinearGradientPackage(), + new RNGetRandomValuesPackage(), mRnReactNativeGutenbergBridgePackage); } diff --git a/packages/react-native-editor/android/app/src/main/java/com/gutenberg/Media.java b/packages/react-native-editor/android/app/src/main/java/com/gutenberg/Media.java new file mode 100644 index 00000000000000..d6eac12d58d22e --- /dev/null +++ b/packages/react-native-editor/android/app/src/main/java/com/gutenberg/Media.java @@ -0,0 +1,65 @@ +package com.gutenberg; + +import androidx.annotation.NonNull; + +import org.wordpress.mobile.ReactNativeGutenbergBridge.GutenbergBridgeJS2Parent.MediaType; +import org.wordpress.mobile.ReactNativeGutenbergBridge.GutenbergBridgeJS2Parent.RNMedia; +import com.facebook.react.bridge.WritableMap; +import com.facebook.react.bridge.WritableNativeMap; + +import java.util.Locale; + +public class Media implements RNMedia { + private int mId; + private String mUrl; + private String mType; + private String mCaption; + + public Media(int id, String url, String type, String caption) { + this.mId = id; + this.mUrl = url; + this.mType = type; + this.mCaption = caption; + } + + public int getId() { + return mId; + } + + public void setId(int id) { + this.mId = id; + } + + public String getUrl() { + return mUrl; + } + + public void setUrl(String url) { + this.mUrl = url; + } + + public String getType() { + return mType; + } + + public void setType(String mediaType) { + this.mType = mediaType; + } + + public String getCaption() { + return mCaption; + } + + public void setCaption(String caption) { + this.mCaption = caption; + } + + public WritableMap toMap() { + WritableMap map = new WritableNativeMap(); + map.putInt("id", mId); + map.putString("url", mUrl); + map.putString("type", mType); + map.putString("caption", mCaption); + return map; + } +} diff --git a/packages/react-native-editor/android/settings.gradle b/packages/react-native-editor/android/settings.gradle index f7ed873aa3b227..f7ae4dfa566f50 100644 --- a/packages/react-native-editor/android/settings.gradle +++ b/packages/react-native-editor/android/settings.gradle @@ -12,5 +12,7 @@ include ':react-native-svg' project(':react-native-svg').projectDir = new File(rootProject.projectDir, '../../../node_modules/react-native-svg/android') include ':react-native-linear-gradient' project(':react-native-linear-gradient').projectDir = new File(rootProject.projectDir, '../../../node_modules/react-native-linear-gradient/android') +include ':react-native-get-random-values' +project(':react-native-get-random-values').projectDir = new File(rootProject.projectDir, '../../../node_modules/react-native-get-random-values/android') include ':app' diff --git a/packages/react-native-editor/bin/po2android.js b/packages/react-native-editor/bin/po2android.js index 1005933f90dd62..7021c014e4485f 100755 --- a/packages/react-native-editor/bin/po2android.js +++ b/packages/react-native-editor/bin/po2android.js @@ -45,6 +45,23 @@ function escapeResourceXML( unsafeXMLValue ) { } ); } +/** + * Android specifics replacements. + * + * @param {string} XMLValue input to apply replacements. + * @return {string} valid string passing Android linter rules. + */ +function androidReplacements( XMLValue ) { + return XMLValue.replace( /(-|\.\.\.)/gm, function( character ) { + switch ( character ) { + case '-': + return '–'; // Android lint rule: TypographyDashes. + case '...': + return '…'; // Android lint rule: TypographyEllipsis + } + } ); +} + /** * Generate a unique string identifier to use as the `name` property in our xml. * Try using the string first by stripping any non-alphanumeric characters and cropping it @@ -97,9 +114,11 @@ function po2Android( poInput ) { return result; } const uniqueName = getUniqueName( translation.msgid ); - const escapedValue = escapeResourceXML( translation.msgid ); - const escapedValuePlural = escapeResourceXML( - translation.msgid_plural || '' + const escapedValue = androidReplacements( + escapeResourceXML( translation.msgid ) + ); + const escapedValuePlural = androidReplacements( + escapeResourceXML( translation.msgid_plural || '' ) ); const comment = translation.comments.extracted || ''; let localizedEntry = ''; diff --git a/packages/react-native-editor/ios/Podfile b/packages/react-native-editor/ios/Podfile index b5ea90975dfd00..5835993eb9d21c 100644 --- a/packages/react-native-editor/ios/Podfile +++ b/packages/react-native-editor/ios/Podfile @@ -38,6 +38,8 @@ target 'gutenberg' do pod 'glog', :podspec => '../../../node_modules/react-native/third-party-podspecs/glog.podspec' pod 'Folly', :podspec => '../../../node_modules/react-native/third-party-podspecs/Folly.podspec' pod 'RNTAztecView', :path => '../../react-native-aztec/RNTAztecView.podspec' + #Use for testing non official versions of Aztec + #pod 'WordPress-Aztec-iOS', :git => '../../https://github.com/wordpress-mobile/WordPress-Aztec-iOS.git', :commit => 'edf1c9ae758b946e76bb9de6efc9135d2c2a4b43' pod 'Gutenberg', :path => '../../react-native-bridge/Gutenberg.podspec' target 'gutenbergTests' do diff --git a/packages/react-native-editor/ios/Podfile.lock b/packages/react-native-editor/ios/Podfile.lock index 9ae849cd4aa4f7..5e7e8312bbf3d7 100644 --- a/packages/react-native-editor/ios/Podfile.lock +++ b/packages/react-native-editor/ios/Podfile.lock @@ -21,7 +21,7 @@ PODS: - DoubleConversion - glog - glog (0.3.5) - - Gutenberg (7.7.1): + - Gutenberg (7.9.1): - React (= 0.61.5) - React-CoreModules (= 0.61.5) - React-RCTImage (= 0.61.5) @@ -189,6 +189,8 @@ PODS: - React-cxxreact (= 0.61.5) - React-jsi (= 0.61.5) - React-jsinspector (0.61.5) + - react-native-get-random-values (1.4.0): + - React - react-native-keyboard-aware-scroll-view (0.8.8): - React - react-native-safe-area (0.5.1): @@ -241,8 +243,8 @@ PODS: - React - RNTAztecView (0.1.11): - React-Core - - WordPress-Aztec-iOS (= 1.16.0) - - WordPress-Aztec-iOS (1.16.0) + - WordPress-Aztec-iOS (~> 1.17.1) + - WordPress-Aztec-iOS (1.17.1) - Yoga (1.14.0) DEPENDENCIES: @@ -264,6 +266,7 @@ DEPENDENCIES: - React-jsi (from `../../../node_modules/react-native/ReactCommon/jsi`) - React-jsiexecutor (from `../../../node_modules/react-native/ReactCommon/jsiexecutor`) - React-jsinspector (from `../../../node_modules/react-native/ReactCommon/jsinspector`) + - react-native-get-random-values (from `../node_modules/react-native-get-random-values`) - react-native-keyboard-aware-scroll-view (from `../../../node_modules/react-native-keyboard-aware-scroll-view`) - react-native-safe-area (from `../../../node_modules/react-native-safe-area`) - "react-native-slider (from `../../../node_modules/@react-native-community/slider`)" @@ -322,6 +325,8 @@ EXTERNAL SOURCES: :path: "../../../node_modules/react-native/ReactCommon/jsiexecutor" React-jsinspector: :path: "../../../node_modules/react-native/ReactCommon/jsinspector" + react-native-get-random-values: + :path: "../node_modules/react-native-get-random-values" react-native-keyboard-aware-scroll-view: :path: "../../../node_modules/react-native-keyboard-aware-scroll-view" react-native-safe-area: @@ -367,7 +372,7 @@ SPEC CHECKSUMS: FBReactNativeSpec: 118d0d177724c2d67f08a59136eb29ef5943ec75 Folly: 30e7936e1c45c08d884aa59369ed951a8e68cf51 glog: 1f3da668190260b06b429bb211bfbee5cd790c28 - Gutenberg: 947a15dae17e75ac0b022ac51b5cb5d8b58f6409 + Gutenberg: ca6b343ebd1e6d0ba57215d02568b391612dc557 RCTRequired: b153add4da6e7dbc44aebf93f3cf4fcae392ddf1 RCTTypeSafety: 9aa1b91d7f9310fc6eadc3cf95126ffe818af320 React: b6a59ef847b2b40bb6e0180a97d0ca716969ac78 @@ -377,6 +382,7 @@ SPEC CHECKSUMS: React-jsi: cb2cd74d7ccf4cffb071a46833613edc79cdf8f7 React-jsiexecutor: d5525f9ed5f782fdbacb64b9b01a43a9323d2386 React-jsinspector: fa0ecc501688c3c4c34f28834a76302233e29dc0 + react-native-get-random-values: 2b7500cdb68066aba87cdccd97067c29e16ffe95 react-native-keyboard-aware-scroll-view: ffa9152671fec9a571197ed2d02e0fcb90206e60 react-native-safe-area: e8230b0017d76c00de6b01e2412dcf86b127c6a3 react-native-slider: f81b89fa0c1f9a65742d33f889a194ca6653a985 @@ -393,10 +399,10 @@ SPEC CHECKSUMS: ReactCommon: 198c7c8d3591f975e5431bec1b0b3b581aa1c5dd ReactNativeDarkMode: f61376360c5d983907e5c316e8e1c853a8c2f348 RNSVG: 68a534a5db06dcbdaebfd5079349191598caef7b - RNTAztecView: 4e64576a03d9e578ad6ee091811a74b33ddbe35b - WordPress-Aztec-iOS: 64a2989d25befb5ce086fac440315f696026ffd5 + RNTAztecView: 922113903205678b6d8780fa844d35892ffab01a + WordPress-Aztec-iOS: 319620514af963ca519bd83b96a2c0ebdf3a0f03 Yoga: f2a7cd4280bfe2cca5a7aed98ba0eb3d1310f18b -PODFILE CHECKSUM: 6f29befa4340201780fd76791bfdf5e85ce42be8 +PODFILE CHECKSUM: d6a23ca37a82e9ae3c2e6b996f5643a59c271c44 COCOAPODS: 1.8.4 diff --git a/packages/react-native-editor/ios/gutenberg.xcodeproj/project.pbxproj b/packages/react-native-editor/ios/gutenberg.xcodeproj/project.pbxproj index 686f78266ee481..372f8f3a2380a6 100644 --- a/packages/react-native-editor/ios/gutenberg.xcodeproj/project.pbxproj +++ b/packages/react-native-editor/ios/gutenberg.xcodeproj/project.pbxproj @@ -489,6 +489,7 @@ "${BUILT_PRODUCTS_DIR}/WordPress-Aztec-iOS/Aztec.framework", "${BUILT_PRODUCTS_DIR}/Yoga/yoga.framework", "${BUILT_PRODUCTS_DIR}/glog/glog.framework", + "${BUILT_PRODUCTS_DIR}/react-native-get-random-values/react_native_get_random_values.framework", "${BUILT_PRODUCTS_DIR}/react-native-keyboard-aware-scroll-view/react_native_keyboard_aware_scroll_view.framework", "${BUILT_PRODUCTS_DIR}/react-native-safe-area/react_native_safe_area.framework", "${BUILT_PRODUCTS_DIR}/react-native-slider/react_native_slider.framework", @@ -523,6 +524,7 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Aztec.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/yoga.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/glog.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/react_native_get_random_values.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/react_native_keyboard_aware_scroll_view.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/react_native_safe_area.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/react_native_slider.framework", diff --git a/packages/react-native-editor/ios/gutenberg/GutenbergViewController.swift b/packages/react-native-editor/ios/gutenberg/GutenbergViewController.swift index 941c23df2b1d14..9539f149f727e9 100644 --- a/packages/react-native-editor/ios/gutenberg/GutenbergViewController.swift +++ b/packages/react-native-editor/ios/gutenberg/GutenbergViewController.swift @@ -79,16 +79,16 @@ extension GutenbergViewController: GutenbergBridgeDelegate { case .image: if(allowMultipleSelection) { callback([MediaInfo(id: 1, url: "https://cldup.com/cXyG__fTLN.jpg", type: "image"), - MediaInfo(id: 3, url: "https://cldup.com/cXyG__fTLN.jpg", type: "image")]) + MediaInfo(id: 3, url: "https://cldup.com/cXyG__fTLN.jpg", type: "image", caption: "Mountain")]) } else { - callback([MediaInfo(id: 1, url: "https://cldup.com/cXyG__fTLN.jpg", type: "image")]) + callback([MediaInfo(id: 1, url: "https://cldup.com/cXyG__fTLN.jpg", type: "image", caption: "Mountain")]) } case .video: if(allowMultipleSelection) { callback([MediaInfo(id: 2, url: "https://i.cloudup.com/YtZFJbuQCE.mov", type: "video"), MediaInfo(id: 4, url: "https://i.cloudup.com/YtZFJbuQCE.mov", type: "video")]) } else { - callback([MediaInfo(id: 2, url: "https://i.cloudup.com/YtZFJbuQCE.mov", type: "video")]) + callback([MediaInfo(id: 2, url: "https://i.cloudup.com/YtZFJbuQCE.mov", type: "video", caption: "Cloudup")]) } default: break diff --git a/packages/react-native-editor/package.json b/packages/react-native-editor/package.json index 5429f1da2c61db..2fbd011c1b9b0c 100644 --- a/packages/react-native-editor/package.json +++ b/packages/react-native-editor/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/react-native-editor", - "version": "1.21.0", + "version": "1.26.0", "description": "Mobile WordPress gutenberg editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -29,6 +29,7 @@ "dependencies": { "@babel/runtime": "^7.7.7", "@react-native-community/slider": "git+https://github.com/wordpress-mobile/react-native-slider.git#5ad284d92b8d886e366445bf215be741ed53ddc6", + "@wordpress/components": "file:../components", "@wordpress/data": "file:../data", "@wordpress/edit-post": "file:../edit-post", "@wordpress/element": "file:../element", @@ -48,6 +49,7 @@ "postinstall-prepare": "^1.0.1", "react-native": "0.61.5", "react-native-dark-mode": "git+https://github.com/wordpress-mobile/react-native-dark-mode.git#f09bf1480e7b34536413ab3300f29e4375edb2c6", + "react-native-get-random-values": "^1.4.0", "react-native-hr": "git+https://github.com/Riglerr/react-native-hr.git#2d01a5cf77212d100e8b99e0310cce5234f977b3", "react-native-keyboard-aware-scroll-view": "git+https://github.com/wordpress-mobile/react-native-keyboard-aware-scroll-view.git#gb-v0.8.8", "react-native-linear-gradient": "git+https://github.com/wordpress-mobile/react-native-linear-gradient.git#52bf43077171cff8714ce3e0155f3ebb7f55bc37", @@ -56,7 +58,7 @@ "react-native-sass-transformer": "^1.1.1", "react-native-svg": "git+https://github.com/wordpress-mobile/react-native-svg.git#a628e92990a2404e30a0086f168bd2b5b7b4ce96", "react-native-url-polyfill": "^1.1.2", - "react-native-video": "git+https://github.com/wordpress-mobile/react-native-video.git#c43bdf6b06d361da399b98b8d2e32b578fa188ac", + "react-native-video": "git+https://github.com/wordpress-mobile/react-native-video.git#6cdaddd9c81ebe2da5b28412d389cc105e156948", "wd": "^1.11.1" }, "publishConfig": { @@ -81,8 +83,8 @@ "install:wpcli": "(test -x bin/wp-cli.phar || curl -Ls https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar -o bin/wp-cli.phar && chmod +x bin/wp-cli.phar) && bin/wp-cli.phar --info", "prewp": "npm run install:wpcli", "wp": "php -d memory_limit=512M bin/wp-cli.phar", - "makepot:android": "npm run wp i18n make-pot ./gutenberg/packages --include=*.native.js,*.android.js --exclude=test/* --subtract=./gutenberg.pot --ignore-domain gutenberg-android.pot", - "makepot:ios": "npm run wp i18n make-pot ./gutenberg/packages --include=*.native.js,*.ios.js --exclude=test/* --subtract=./gutenberg.pot --ignore-domain gutenberg-ios.pot", + "makepot:android": "test -f gutenberg.pot && npm run wp i18n make-pot ./gutenberg/packages --include=*.native.js,*.android.js --exclude=test/* --subtract=./gutenberg.pot --ignore-domain gutenberg-android.pot", + "makepot:ios": "test -f gutenberg.pot && npm run wp i18n make-pot ./gutenberg/packages --include=*.native.js,*.ios.js --exclude=test/* --subtract=./gutenberg.pot --ignore-domain gutenberg-ios.pot", "premakepot:gutenberg": "npm run clean:gutenberg && npm run build:gutenberg", "makepot:gutenberg": "npm run wp i18n make-pot ./gutenberg/build --ignore-domain gutenberg.pot", "postmakepot:gutenberg": "npm run clean:gutenberg", diff --git a/packages/react-native-editor/src/api-fetch-setup.js b/packages/react-native-editor/src/api-fetch-setup.js index 358b4aa2482d13..6a396732f49751 100644 --- a/packages/react-native-editor/src/api-fetch-setup.js +++ b/packages/react-native-editor/src/api-fetch-setup.js @@ -43,7 +43,10 @@ const fetchHandler = ( { path }, retries = 20, retryCount = 1 ) => { }; export const isPathSupported = ( path ) => - [ /wp\/v2\/media\/?\d*?.*/i ].some( ( pattern ) => pattern.test( path ) ); + [ + /wp\/v2\/(media|categories)\/?\d*?.*/i, + /wpcom\/v2\/gutenberg\/.*/i, + ].some( ( pattern ) => pattern.test( path ) ); export default () => { apiFetch.setFetchHandler( ( options ) => fetchHandler( options ) ); diff --git a/packages/react-native-editor/src/index.js b/packages/react-native-editor/src/index.js index 19a144395396b5..cdac46e3a1cf88 100644 --- a/packages/react-native-editor/src/index.js +++ b/packages/react-native-editor/src/index.js @@ -1,6 +1,7 @@ /** * External dependencies */ +import 'react-native-get-random-values'; // This library works as a polyfill for the global crypto.getRandomValues which is needed by `uuid` version 7.0.0 import { AppRegistry, I18nManager } from 'react-native'; /** * WordPress dependencies diff --git a/packages/react-native-editor/src/initial-html.js b/packages/react-native-editor/src/initial-html.js index 82568ab42a5209..1ec7eef7fc2cc5 100644 --- a/packages/react-native-editor/src/initial-html.js +++ b/packages/react-native-editor/src/initial-html.js @@ -221,4 +221,6 @@ else: <p class="has-text-color has-text-align-center has-large-font-size has-very-light-gray-color">Cool cover</p> <!-- /wp:paragraph --></div></div> <!-- /wp:cover --> + +<!-- wp:latest-posts {"displayPostContent":true,"displayPostDate":true} /--> `; diff --git a/packages/react-native-editor/src/test/api-fetch-setup.test.js b/packages/react-native-editor/src/test/api-fetch-setup.test.js index bbe0ad9902d669..c7d5b230fbf8fd 100644 --- a/packages/react-native-editor/src/test/api-fetch-setup.test.js +++ b/packages/react-native-editor/src/test/api-fetch-setup.test.js @@ -9,6 +9,7 @@ const supportedPaths = [ 'wp/v2/media/54/', 'wp/v2/media/', 'wp/v2/media?context=edit&_locale=user', + 'wp/v2/categories/', ]; const unsupportedPaths = [ diff --git a/packages/redux-routine/package.json b/packages/redux-routine/package.json index 89db00b09fff9f..620ab50e9fdf87 100644 --- a/packages/redux-routine/package.json +++ b/packages/redux-routine/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/redux-routine", - "version": "3.7.0", + "version": "3.8.0", "description": "Redux middleware for generator coroutines.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -24,7 +24,7 @@ "react-native": "src/index", "sideEffects": false, "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "is-promise": "^2.1.0", "lodash": "^4.17.15", "rungen": "^0.3.2" diff --git a/packages/redux-routine/src/test/index.js b/packages/redux-routine/src/test/index.js index 6c2888e00a7514..b240f8740894f2 100644 --- a/packages/redux-routine/src/test/index.js +++ b/packages/redux-routine/src/test/index.js @@ -60,6 +60,7 @@ describe( 'createMiddleware', () => { try { yield { type: 'WAIT_FAIL' }; } catch ( error ) { + // eslint-disable-next-line jest/no-try-expect expect( error ).toBe( 'Message' ); } } @@ -80,6 +81,7 @@ describe( 'createMiddleware', () => { try { yield { type: 'WAIT_FAIL' }; } catch ( error ) { + // eslint-disable-next-line jest/no-try-expect expect( error.message ).toBe( 'Message' ); } } @@ -106,6 +108,7 @@ describe( 'createMiddleware', () => { try { yield { type: 'WAIT_FAIL' }; } catch ( error ) { + // eslint-disable-next-line jest/no-try-expect expect( error.message ).toBe( 'Message' ); return null; } diff --git a/packages/rich-text/package.json b/packages/rich-text/package.json index 3783992e5bfd36..83b87751ebb470 100644 --- a/packages/rich-text/package.json +++ b/packages/rich-text/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/rich-text", - "version": "3.12.1", + "version": "3.14.1", "description": "Rich text value and manipulation API.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -21,7 +21,7 @@ "module": "build-module/index.js", "react-native": "src/index", "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/compose": "file:../compose", "@wordpress/data": "file:../data", "@wordpress/deprecated": "file:../deprecated", @@ -31,7 +31,7 @@ "@wordpress/keycodes": "file:../keycodes", "classnames": "^2.2.5", "lodash": "^4.17.15", - "memize": "^1.0.5", + "memize": "^1.1.0", "rememo": "^3.0.0" }, "publishConfig": { diff --git a/packages/rich-text/src/component/boundary-style.js b/packages/rich-text/src/component/boundary-style.js index cba9eeaf6b5a3f..3c17da53697041 100644 --- a/packages/rich-text/src/component/boundary-style.js +++ b/packages/rich-text/src/component/boundary-style.js @@ -3,15 +3,6 @@ */ import { useEffect } from '@wordpress/element'; -/** - * Global stylesheet shared by all RichText instances. - */ -const globalStyle = document.createElement( 'style' ); - -const boundarySelector = '*[data-rich-text-format-boundary]'; - -document.head.appendChild( globalStyle ); - /** * Calculates and renders the format boundary style when the active formats * change. @@ -24,19 +15,31 @@ export function BoundaryStyle( { activeFormats, forwardedRef } ) { return; } + const boundarySelector = '*[data-rich-text-format-boundary]'; const element = forwardedRef.current.querySelector( boundarySelector ); if ( ! element ) { return; } - const computedStyle = window.getComputedStyle( element ); + const { ownerDocument } = element; + const { defaultView } = ownerDocument; + const computedStyle = defaultView.getComputedStyle( element ); const newColor = computedStyle.color .replace( ')', ', 0.2)' ) .replace( 'rgb', 'rgba' ); const selector = `.rich-text:focus ${ boundarySelector }`; const rule = `background-color: ${ newColor }`; const style = `${ selector } {${ rule }}`; + const globalStyleId = 'rich-text-boundary-style'; + + let globalStyle = ownerDocument.getElementById( globalStyleId ); + + if ( ! globalStyle ) { + globalStyle = ownerDocument.createElement( 'style' ); + globalStyle.id = globalStyleId; + ownerDocument.head.appendChild( globalStyle ); + } if ( globalStyle.innerHTML !== style ) { globalStyle.innerHTML = style; diff --git a/packages/rich-text/src/component/index.js b/packages/rich-text/src/component/index.js index baa8826f12879e..cd174b2baaabba 100644 --- a/packages/rich-text/src/component/index.js +++ b/packages/rich-text/src/component/index.js @@ -40,12 +40,7 @@ import { isEmptyLine } from '../is-empty'; import withFormatTypes from './with-format-types'; import { BoundaryStyle } from './boundary-style'; import { InlineWarning } from './inline-warning'; - -/** - * Browser dependencies - */ - -const { getSelection, getComputedStyle } = window; +import { insert } from '../insert'; /** @typedef {import('@wordpress/element').WPSyntheticEvent} WPSyntheticEvent */ @@ -113,9 +108,11 @@ function createPrepareEditableTree( props, prefix ) { /** * If the selection is set on the placeholder element, collapse the selection to * the start (before the placeholder). + * + * @param {Window} defaultView */ -function fixPlaceholderSelection() { - const selection = window.getSelection(); +function fixPlaceholderSelection( defaultView ) { + const selection = defaultView.getSelection(); const { anchorNode, anchorOffset } = selection; if ( anchorNode.nodeType !== anchorNode.ELEMENT_NODE ) { @@ -142,6 +139,8 @@ class RichText extends Component { constructor( { value, selectionStart, selectionEnd } ) { super( ...arguments ); + this.getDocument = this.getDocument.bind( this ); + this.getWindow = this.getWindow.bind( this ); this.onFocus = this.onFocus.bind( this ); this.onBlur = this.onBlur.bind( this ); this.onChange = this.onChange.bind( this ); @@ -186,24 +185,32 @@ class RichText extends Component { } componentWillUnmount() { - document.removeEventListener( + this.getDocument().removeEventListener( 'selectionchange', this.onSelectionChange ); - window.cancelAnimationFrame( this.rafId ); + this.getWindow().cancelAnimationFrame( this.rafId ); } componentDidMount() { this.applyRecord( this.record, { domOnly: true } ); } + getDocument() { + return this.props.forwardedRef.current.ownerDocument; + } + + getWindow() { + return this.getDocument().defaultView; + } + createRecord() { const { __unstableMultilineTag: multilineTag, forwardedRef, preserveWhiteSpace, } = this.props; - const selection = getSelection(); + const selection = this.getWindow().getSelection(); const range = selection.rangeCount > 0 ? selection.getRangeAt( 0 ) : null; @@ -251,6 +258,7 @@ class RichText extends Component { formatTypes, onPaste, __unstableIsSelected: isSelected, + __unstableDisableFormats, } = this.props; const { activeFormats = [] } = this.state; @@ -293,6 +301,11 @@ class RichText extends Component { window.console.log( 'Received HTML:\n\n', html ); window.console.log( 'Received plain text:\n\n', plainText ); + if ( __unstableDisableFormats ) { + this.onChange( insert( this.record, plainText ) ); + return; + } + const record = this.record; const transformed = formatTypes.reduce( ( accumlator, { __unstablePasteRule } ) => { @@ -401,9 +414,14 @@ class RichText extends Component { // frame. The event listener for selection changes may be added too late // at this point, but this focus event is still too early to calculate // the selection. - this.rafId = window.requestAnimationFrame( this.onSelectionChange ); + this.rafId = this.getWindow().requestAnimationFrame( + this.onSelectionChange + ); - document.addEventListener( 'selectionchange', this.onSelectionChange ); + this.getDocument().addEventListener( + 'selectionchange', + this.onSelectionChange + ); if ( this.props.setFocusedElement ) { deprecated( 'wp.blockEditor.RichText setFocusedElement prop', { @@ -414,7 +432,7 @@ class RichText extends Component { } onBlur() { - document.removeEventListener( + this.getDocument().removeEventListener( 'selectionchange', this.onSelectionChange ); @@ -514,7 +532,7 @@ class RichText extends Component { // Do not update the selection when characters are being composed as // this rerenders the component and might distroy internal browser // editing state. - document.removeEventListener( + this.getDocument().removeEventListener( 'selectionchange', this.onSelectionChange ); @@ -526,7 +544,10 @@ class RichText extends Component { // input event after composition. this.onInput( { inputType: 'insertText' } ); // Tracking selection changes can be resumed. - document.addEventListener( 'selectionchange', this.onSelectionChange ); + this.getDocument().addEventListener( + 'selectionchange', + this.onSelectionChange + ); } /** @@ -569,7 +590,7 @@ class RichText extends Component { // element, in which case the caret is not visible. We need to set // the caret before the placeholder if that's the case. if ( value.text.length === 0 && start === 0 ) { - fixPlaceholderSelection(); + fixPlaceholderSelection( this.getWindow() ); } return; @@ -830,7 +851,7 @@ class RichText extends Component { const { text, formats, start, end, activeFormats = [] } = value; const collapsed = isCollapsed( value ); // To do: ideally, we should look at visual position instead. - const { direction } = getComputedStyle( + const { direction } = this.getWindow().getComputedStyle( this.props.forwardedRef.current ); const reverseKey = direction === 'rtl' ? RIGHT : LEFT; @@ -933,8 +954,8 @@ class RichText extends Component { const { parentNode } = target; const index = Array.from( parentNode.childNodes ).indexOf( target ); - const range = target.ownerDocument.createRange(); - const selection = getSelection(); + const range = this.getDocument().createRange(); + const selection = this.getWindow().getSelection(); range.setStart( target.parentNode, index ); range.setEnd( target.parentNode, index + 1 ); diff --git a/packages/rich-text/src/component/index.native.js b/packages/rich-text/src/component/index.native.js index 9138477e45d2ff..a94e384c76e10f 100644 --- a/packages/rich-text/src/component/index.native.js +++ b/packages/rich-text/src/component/index.native.js @@ -811,7 +811,7 @@ export class RichText extends Component { ...style, ...( this.isIOS && minWidth && maxWidth ? { width } - : {} ), + : { maxWidth } ), minHeight: this.state.height, } } text={ { diff --git a/packages/rich-text/src/component/inline-warning.js b/packages/rich-text/src/component/inline-warning.js index d74858dd912b66..00598b4d7c544d 100644 --- a/packages/rich-text/src/component/inline-warning.js +++ b/packages/rich-text/src/component/inline-warning.js @@ -6,9 +6,9 @@ import { useEffect } from '@wordpress/element'; export function InlineWarning( { forwardedRef } ) { useEffect( () => { if ( process.env.NODE_ENV === 'development' ) { - const computedStyle = window.getComputedStyle( - forwardedRef.current - ); + const target = forwardedRef.current; + const { defaultView } = target.ownerDocument; + const computedStyle = defaultView.getComputedStyle( target ); if ( computedStyle.display === 'inline' ) { // eslint-disable-next-line no-console diff --git a/packages/rich-text/src/create.js b/packages/rich-text/src/create.js index ca25ef8e09be10..89c8d298da6865 100644 --- a/packages/rich-text/src/create.js +++ b/packages/rich-text/src/create.js @@ -16,12 +16,6 @@ import { ZWNBSP, } from './special-characters'; -/** - * Browser dependencies - */ - -const { TEXT_NODE, ELEMENT_NODE } = window.Node; - function createEmptyValue() { return { formats: [], @@ -160,6 +154,8 @@ export function create( { } if ( typeof html === 'string' && html.length > 0 ) { + // It does not matter which document this is, we're just using it to + // parse. element = createElement( document, html ); } @@ -208,7 +204,7 @@ function accumulateSelection( accumulator, node, range, value ) { if ( value.start !== undefined ) { accumulator.start = currentLength + value.start; // Range indicates that the current node has selection. - } else if ( node === startContainer && node.nodeType === TEXT_NODE ) { + } else if ( node === startContainer && node.nodeType === node.TEXT_NODE ) { accumulator.start = currentLength + startOffset; // Range indicates that the current node is selected. } else if ( @@ -231,7 +227,7 @@ function accumulateSelection( accumulator, node, range, value ) { if ( value.end !== undefined ) { accumulator.end = currentLength + value.end; // Range indicates that the current node has selection. - } else if ( node === endContainer && node.nodeType === TEXT_NODE ) { + } else if ( node === endContainer && node.nodeType === node.TEXT_NODE ) { accumulator.end = currentLength + endOffset; // Range indicates that the current node is selected. } else if ( @@ -342,7 +338,7 @@ function createFromElement( { const node = element.childNodes[ index ]; const type = node.nodeName.toLowerCase(); - if ( node.nodeType === TEXT_NODE ) { + if ( node.nodeType === node.TEXT_NODE ) { let filter = removePadding; if ( ! preserveWhiteSpace ) { @@ -361,7 +357,7 @@ function createFromElement( { continue; } - if ( node.nodeType !== ELEMENT_NODE ) { + if ( node.nodeType !== node.ELEMENT_NODE ) { continue; } diff --git a/packages/rich-text/src/to-dom.js b/packages/rich-text/src/to-dom.js index 0a63e94a95e3ab..a0d57617a0d0b3 100644 --- a/packages/rich-text/src/to-dom.js +++ b/packages/rich-text/src/to-dom.js @@ -5,12 +5,6 @@ import { toTree } from './to-tree'; import { createElement } from './create-element'; -/** - * Browser dependencies - */ - -const { TEXT_NODE } = window.Node; - /** * Creates a path as an array of indices from the given root node to the given * node. @@ -59,18 +53,6 @@ function getNodeByPath( node, path ) { }; } -/** - * Returns a new instance of a DOM tree upon which RichText operations can be - * applied. - * - * Note: The current implementation will return a shared reference, reset on - * each call to `createEmpty`. Therefore, you should not hold a reference to - * the value to operate upon asynchronously, as it may have unexpected results. - * - * @return {Object} RichText tree. - */ -const createEmpty = () => createElement( document, '' ); - function append( element, child ) { if ( typeof child === 'string' ) { child = element.ownerDocument.createTextNode( child ); @@ -101,8 +83,8 @@ function getParent( { parentNode } ) { return parentNode; } -function isText( { nodeType } ) { - return nodeType === TEXT_NODE; +function isText( node ) { + return node.nodeType === node.TEXT_NODE; } function getText( { nodeValue } ) { @@ -119,6 +101,7 @@ export function toDom( { prepareEditableTree, isEditableTree = true, placeholder, + doc = document, } ) { let startPath = []; let endPath = []; @@ -130,6 +113,18 @@ export function toDom( { }; } + /** + * Returns a new instance of a DOM tree upon which RichText operations can be + * applied. + * + * Note: The current implementation will return a shared reference, reset on + * each call to `createEmpty`. Therefore, you should not hold a reference to + * the value to operate upon asynchronously, as it may have unexpected results. + * + * @return {Object} RichText tree. + */ + const createEmpty = () => createElement( doc, '' ); + const tree = toTree( { value, multilineTag, @@ -186,6 +181,7 @@ export function apply( { multilineTag, prepareEditableTree, placeholder, + doc: current.ownerDocument, } ); applyValue( body, current ); @@ -207,7 +203,7 @@ export function applyValue( future, current ) { } else if ( ! currentChild.isEqualNode( futureChild ) ) { if ( currentChild.nodeName !== futureChild.nodeName || - ( currentChild.nodeType === TEXT_NODE && + ( currentChild.nodeType === currentChild.TEXT_NODE && currentChild.data !== futureChild.data ) ) { current.replaceChild( futureChild, currentChild ); @@ -282,8 +278,9 @@ export function applySelection( { startPath, endPath }, current ) { current, endPath ); - const selection = window.getSelection(); const { ownerDocument } = current; + const { defaultView } = ownerDocument; + const selection = defaultView.getSelection(); const range = ownerDocument.createRange(); range.setStart( startContainer, startOffset ); @@ -305,21 +302,15 @@ export function applySelection( { startPath, endPath }, current ) { // This function is not intended to cause a shift in focus. Since the above // selection manipulations may shift focus, ensure that focus is restored to - // its previous state. `activeElement` can be `null` or the body element if - // there is no focus, which is accounted for here in the explicit `blur` to - // restore to a state of non-focus. - if ( activeElement !== document.activeElement ) { + // its previous state. + if ( activeElement !== ownerDocument.activeElement ) { // The `instanceof` checks protect against edge cases where the focused // element is not of the interface HTMLElement (does not have a `focus` // or `blur` property). // // See: https://github.com/Microsoft/TypeScript/issues/5901#issuecomment-431649653 - if ( activeElement ) { - if ( activeElement instanceof window.HTMLElement ) { - activeElement.focus(); - } - } else if ( document.activeElement instanceof window.HTMLElement ) { - document.activeElement.blur(); + if ( activeElement instanceof defaultView.HTMLElement ) { + activeElement.focus(); } } } diff --git a/packages/scripts/CHANGELOG.md b/packages/scripts/CHANGELOG.md index ed97fc9010edc9..b9bafde585be29 100644 --- a/packages/scripts/CHANGELOG.md +++ b/packages/scripts/CHANGELOG.md @@ -1,5 +1,26 @@ ## Master +### Breaking Changes + +- The bundled `puppeteer` (`^2.0.0`) dependency has been replaced with `puppeteer-core` in version `3.0.0`. Puppeteer uses Chromium v81 instead of Chromium v79. See the [full list of changes](https://github.com/puppeteer/puppeteer/releases/tag/v3.0.0). It also allowed preventing Chromium installation together with `@wordpress/scripts`. It happens now on-demand when running `test-e2e` script, and it re-triggers only when a new version is required. + +### Bug fix + +- The bundled `npm-package-json-lint` dependency has been updated from requiring `^4.0.3` to requiring `^5.0.0` ([#21597](https://github.com/WordPress/gutenberg/pull/21597)). [Breaking changes](https://npmpackagejsonlint.org/docs/en/v4-to-v5) don't break anything in this package. It fixes the abrupt shutdown when `"description"` field in `package.json` is empty. +- Update `check-licenses` script to parse JSON dependency tree recursively so sub-dependencies of packages passed in `--ignore` flag are ignored as well. + +## 8.0.0 (2020-04-15) + +### Breaking Changes + +- The bundled `jest` dependency has been updated from requiring `^24.9.0` to requiring `^25.3.0` (see [Breaking Changes](https://jestjs.io/blog/2020/01/21/jest-25), [#20766](https://github.com/WordPress/gutenberg/pull/20766)). + +### Enhancements + +- The bundled `eslint` dependency has been updated from requiring `^6.1.0` to requiring `^6.8.0` ([#21424](https://github.com/WordPress/gutenberg/pull/21424)). + +## 7.2.0 (2020-04-01) + ### Enhancements - Incompatibility between `@svgr/webpack` in version `4.3.3` and `url-loader` in version `3.0.0` was fixed by bumping `@svgr/webpack` to `^5.2.0`. diff --git a/packages/scripts/README.md b/packages/scripts/README.md index 42df6dd14a78d8..3c49a764787ed6 100644 --- a/packages/scripts/README.md +++ b/packages/scripts/README.md @@ -50,7 +50,7 @@ It might also be a good idea to get familiar with the [JavaScript Build Setup tu To update an existing project to a new version of `@wordpress/scripts`, open the [changelog](https://github.com/WordPress/gutenberg/blob/master/packages/scripts/CHANGELOG.md), find the version you’re currently on (check `package.json` in the top-level directory of your project), and apply the migration instructions for the newer versions. -In most cases bumping the `@wordpress/scripts` version in `package.json` and running `npm install` in the root folder of your project should be enough, but it’s good to check the [changelog](https://github.com/WordPress/gutenberg/blob/master/packages/scripts/CHANGELOG.md) for potential breaking changes. There is also `update-packages` script included in this package that aims to automate the process of updating WordPress dependencies in your projects. +In most cases bumping the `@wordpress/scripts` version in `package.json` and running `npm install` in the root folder of your project should be enough, but it’s good to check the [changelog](https://github.com/WordPress/gutenberg/blob/master/packages/scripts/CHANGELOG.md) for potential breaking changes. There is also `packages-update` script included in this package that aims to automate the process of updating WordPress dependencies in your projects. We commit to keeping the breaking changes minimal so you can upgrade `@wordpress/scripts` as seamless as possible. diff --git a/packages/scripts/config/.eslintrc.js b/packages/scripts/config/.eslintrc.js index b3bb9bce2d2d32..68e37cf71d9cc5 100644 --- a/packages/scripts/config/.eslintrc.js +++ b/packages/scripts/config/.eslintrc.js @@ -1,9 +1,3 @@ -/** - * Internal dependencies - */ -const defaultPrettierConfig = require( './.prettierrc' ); -const { hasPrettierConfig } = require( '../utils' ); - const eslintConfig = { root: true, extends: [ @@ -17,16 +11,4 @@ const eslintConfig = { ], }; -if ( ! hasPrettierConfig() ) { - eslintConfig.rules = { - 'prettier/prettier': [ - 'error', - defaultPrettierConfig, - { - usePrettierrc: false, - }, - ], - }; -} - module.exports = eslintConfig; diff --git a/packages/scripts/package.json b/packages/scripts/package.json index b1aa4e7dd89ae1..6904013ada57b9 100644 --- a/packages/scripts/package.json +++ b/packages/scripts/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/scripts", - "version": "7.1.3", + "version": "8.0.1", "description": "Collection of reusable scripts for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -40,28 +40,28 @@ "@wordpress/jest-preset-default": "file:../jest-preset-default", "@wordpress/npm-package-json-lint-config": "file:../npm-package-json-lint-config", "@wordpress/prettier-config": "file:../prettier-config", - "babel-jest": "^24.9.0", - "babel-loader": "^8.0.6", - "chalk": "^2.4.2", + "babel-jest": "^25.3.0", + "babel-loader": "^8.1.0", + "chalk": "^4.0.0", "check-node-version": "^3.1.1", "command-exists": "^1.2.8", "cross-spawn": "^5.1.0", "decompress-zip": "^0.2.2", "dir-glob": "^3.0.1", - "eslint": "^6.1.0", - "eslint-plugin-markdown": "1.0.1", - "jest": "^24.9.0", - "jest-puppeteer": "^4.3.0", + "eslint": "^6.8.0", + "eslint-plugin-markdown": "^1.0.2", + "got": "^10.7.0", + "jest": "^25.3.0", + "jest-puppeteer": "^4.4.0", "js-yaml": "^3.13.1", "lodash": "^4.17.15", "markdownlint": "^0.18.0", "markdownlint-cli": "^0.21.0", "minimist": "^1.2.0", - "npm-package-json-lint": "^4.0.3", + "npm-package-json-lint": "^5.0.0", "prettier": "npm:wp-prettier@1.19.1", - "puppeteer": "^2.0.0", + "puppeteer": "npm:puppeteer-core@3.0.0", "read-pkg-up": "^1.0.1", - "request": "^2.88.0", "resolve-bin": "^0.4.0", "source-map-loader": "^0.2.4", "sprintf-js": "^1.1.1", diff --git a/packages/scripts/scripts/check-licenses.js b/packages/scripts/scripts/check-licenses.js index acf098cffe63d5..2c554c45699ce4 100644 --- a/packages/scripts/scripts/check-licenses.js +++ b/packages/scripts/scripts/check-licenses.js @@ -3,7 +3,6 @@ */ const spawn = require( 'cross-spawn' ); const { existsSync, readFileSync } = require( 'fs' ); -const { sep } = require( 'path' ); const chalk = require( 'chalk' ); /** @@ -21,6 +20,7 @@ const { getArgFromCLI, hasArgInCLI } = require( '../utils' ); */ const ERROR = chalk.reset.inverse.bold.red( ' ERROR ' ); +const WARNING = chalk.reset.inverse.bold.yellow( ' WARNING ' ); const prod = hasArgInCLI( '--prod' ) || hasArgInCLI( '--production' ); const dev = hasArgInCLI( '--dev' ) || hasArgInCLI( '--development' ); @@ -170,36 +170,59 @@ const checkLicense = ( allowedLicense, licenseType ) => { ); }; -/** - * Returns true if the given module path is not to be ignored for consideration - * in license validation, or false otherwise. - * - * @param {string} moduleName Module path. - * - * @return {boolean} Whether module path is not to be ignored. - */ -const isNotIgnoredModule = ( moduleName ) => - ! ignored.some( ( ignoredItem ) => - // `moduleName` is a file path to the module directory. Assume CLI arg - // is passed as basename of package (directory(s) after node_modules). - // Prefix with sep to avoid false-positives on prefixing variations. - moduleName.endsWith( sep + ignoredItem ) - ); - // Use `npm ls` to grab a list of all the packages. -const child = spawn.sync( 'npm', [ - 'ls', - '--parseable', - ...( prod ? [ '--prod' ] : [] ), - ...( dev ? [ '--dev' ] : [] ), -] ); - -const modules = child.stdout - .toString() - .split( '\n' ) - .filter( isNotIgnoredModule ); - -modules.forEach( ( path ) => { +const child = spawn.sync( + 'npm', + [ + 'ls', + '--json', + '--long', + ...( prod ? [ '--prod' ] : [] ), + ...( dev ? [ '--dev' ] : [] ), + ], + { maxBuffer: 1024 * 1024 * 100 } // output size for prod is ~21 MB and dev is ~76 MB +); + +const result = JSON.parse( child.stdout.toString() ); + +const topLevelDeps = result.dependencies; + +function traverseDepTree( deps ) { + for ( const key in deps ) { + const dep = deps[ key ]; + + if ( ignored.includes( dep.name ) ) { + return; + } + + if ( ! dep.hasOwnProperty( 'path' ) ) { + if ( dep.hasOwnProperty( 'peerMissing' ) ) { + process.stdout.write( + `${ WARNING } Unable to locate path for missing peer dep ${ dep.name }@${ dep.version }. ` + ); + } else { + process.exitCode = 1; + process.stdout.write( + `${ ERROR } Unable to locate path for ${ dep.name }@${ dep.version }. ` + ); + } + } else if ( dep.missing ) { + process.stdout.write( + `${ WARNING } missing dep ${ dep.name }@${ dep.version }. ` + ); + } else { + checkDepLicense( dep.path ); + } + + if ( dep.hasOwnProperty( 'dependencies' ) ) { + traverseDepTree( dep.dependencies ); + } else { + return; + } + } +} + +function checkDepLicense( path ) { if ( ! path ) { return; } @@ -287,4 +310,6 @@ modules.forEach( ( path ) => { `${ ERROR } Module ${ packageInfo.name } has an incompatible license '${ licenseType }'.\n` ); } -} ); +} + +traverseDepTree( topLevelDeps ); diff --git a/packages/scripts/scripts/format-js.js b/packages/scripts/scripts/format-js.js index 5210d114b26a75..60b75a12d82bc8 100644 --- a/packages/scripts/scripts/format-js.js +++ b/packages/scripts/scripts/format-js.js @@ -72,9 +72,11 @@ if ( ! checkResult.success ) { // needed for config, otherwise pass in args to default config in packages // See: https://prettier.io/docs/en/configuration.html let configArgs = []; -// TODO: once setup, use @wordpress/prettier-config if ( ! hasPrettierConfig() ) { - configArgs = [ '--config', fromConfigRoot( '.prettierrc.js' ) ]; + configArgs = [ + '--config', + require.resolve( '@wordpress/prettier-config' ), + ]; } // If `--ignore-path` is not explicitly specified, use the project's or global .eslintignore @@ -101,7 +103,7 @@ if ( fileArgs.length === 0 ) { } // Converts `foo/bar` directory to `foo/bar/**/*.js` -const globArgs = dirGlob( fileArgs, { extensions: [ 'js' ] } ); +const globArgs = dirGlob( fileArgs, { extensions: [ 'js', 'jsx' ] } ); const result = spawn( resolveBin( 'prettier' ), diff --git a/packages/scripts/scripts/test-e2e.js b/packages/scripts/scripts/test-e2e.js index 2cc42f09c4d588..6ab4dabb2b19c9 100644 --- a/packages/scripts/scripts/test-e2e.js +++ b/packages/scripts/scripts/test-e2e.js @@ -14,6 +14,7 @@ process.on( 'unhandledRejection', ( err ) => { */ /* eslint-disable-next-line jest/no-jest-import */ const jest = require( 'jest' ); +const { sync: spawn } = require( 'cross-spawn' ); /** * Internal dependencies @@ -27,6 +28,14 @@ const { hasJestConfig, } = require( '../utils' ); +const result = spawn( 'node', [ require.resolve( 'puppeteer/install' ) ], { + stdio: 'inherit', +} ); + +if ( result.status > 0 ) { + process.exit( result.status ); +} + // Provides a default config path for Puppeteer when jest-puppeteer.config.js // wasn't found at the root of the project or a custom path wasn't defined // using JEST_PUPPETEER_CONFIG environment variable. diff --git a/packages/scripts/utils/env.js b/packages/scripts/utils/env.js index 372ef3479192dc..41fc7fc9932859 100644 --- a/packages/scripts/utils/env.js +++ b/packages/scripts/utils/env.js @@ -2,7 +2,7 @@ * External dependencies */ const { isPlainObject } = require( 'lodash' ); -const request = require( 'request' ); +const got = require( 'got' ); const DecompressZip = require( 'decompress-zip' ); const chalk = require( 'chalk' ); const { sprintf } = require( 'sprintf-js' ); @@ -95,10 +95,9 @@ function downloadWordPressZip() { stdout.write( 'Downloading...\n' ); // Download the archive. - request - .get( - 'https://github.com/WordPress/wordpress-develop/archive/master.zip' - ) + got.stream( + 'https://github.com/WordPress/wordpress-develop/archive/master.zip' + ) .on( 'error', ( error ) => { stdout.write( "ERROR: The zip file couldn't be downloaded.\n" ); stdout.write( error.toString() ); @@ -176,7 +175,7 @@ function buildWordPress( newInstall, fastInstall ) { if ( env.npm_package_wp_env_welcome_build_command ) { const nextStep = sprintf( - '\nRun %s to build the latest version of %s, then open %s to get started!\n', + '\nRun %1$s to build the latest version of %2$s, then open %3$s to get started!\n', chalk.blue( env.npm_package_wp_env_welcome_build_command ), chalk.green( env.npm_package_wp_env_plugin_name ), chalk.blue( currentUrl ) @@ -191,7 +190,7 @@ function buildWordPress( newInstall, fastInstall ) { ); const access = sprintf( - 'Default username: %s, password: %s\n', + 'Default username: %1$s, password: %2$s\n', chalk.blue( 'admin' ), chalk.blue( 'password' ) ); diff --git a/packages/scripts/utils/index.js b/packages/scripts/utils/index.js index 0629a0e21bcab7..2c4957c1d81922 100644 --- a/packages/scripts/utils/index.js +++ b/packages/scripts/utils/index.js @@ -22,11 +22,9 @@ const { } = require( './env' ); const { fromProjectRoot, fromConfigRoot, hasProjectFile } = require( './file' ); const { hasPackageProp } = require( './package' ); -const { camelCaseDash } = require( './string' ); module.exports = { buildWordPress, - camelCaseDash, fromProjectRoot, fromConfigRoot, getArgFromCLI, diff --git a/packages/scripts/utils/string.js b/packages/scripts/utils/string.js deleted file mode 100644 index f44be223dec807..00000000000000 --- a/packages/scripts/utils/string.js +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Given a string, returns a new string with dash separators converted to - * camelCase equivalent. This is not as aggressive as `_.camelCase` in - * converting to uppercase, where Lodash will also capitalize letters - * following numbers. - * - * @param {string} string Input dash-delimited string. - * - * @return {string} Camel-cased string. - */ -function camelCaseDash( string ) { - return string.replace( /-([a-z])/g, ( match, letter ) => - letter.toUpperCase() - ); -} - -module.exports = { - camelCaseDash, -}; diff --git a/packages/scripts/utils/test/string.js b/packages/scripts/utils/test/string.js deleted file mode 100644 index aa0f441186fa11..00000000000000 --- a/packages/scripts/utils/test/string.js +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Internal dependencies - */ -import { camelCaseDash } from '../string'; - -describe( 'string', () => { - describe( 'camelCaseDash', () => { - test( 'does not change a single word', () => { - expect( camelCaseDash( 'blocks' ) ).toBe( 'blocks' ); - expect( camelCaseDash( 'dom' ) ).toBe( 'dom' ); - } ); - - test( 'does not capitalize letters following numbers', () => { - expect( camelCaseDash( 'a11y' ) ).toBe( 'a11y' ); - expect( camelCaseDash( 'i18n' ) ).toBe( 'i18n' ); - } ); - - test( 'converts dashes into camel case', () => { - expect( camelCaseDash( 'api-fetch' ) ).toBe( 'apiFetch' ); - expect( camelCaseDash( 'list-reusable-blocks' ) ).toBe( - 'listReusableBlocks' - ); - } ); - } ); -} ); diff --git a/packages/server-side-render/README.md b/packages/server-side-render/README.md index dcd3d6b2bc5906..b9baee0f813b0a 100644 --- a/packages/server-side-render/README.md +++ b/packages/server-side-render/README.md @@ -81,6 +81,21 @@ Render core/archives preview. ```jsx import ServerSideRender from '@wordpress/server-side-render'; +const MyServerSideRender = () => ( + <ServerSideRender + block="core/archives" + attributes={ { + showPostCounts: true, + displayAsDropdown: false, + } } + /> +); +``` +If imported from the `wp` global, an alias is required to work in JSX. + +```jsx +const { serverSideRender: ServerSideRender } = wp; + const MyServerSideRender = () => ( <ServerSideRender block="core/archives" diff --git a/packages/server-side-render/package.json b/packages/server-side-render/package.json index 142233a1734ed9..2e5bbdfd3f9d48 100644 --- a/packages/server-side-render/package.json +++ b/packages/server-side-render/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/server-side-render", - "version": "1.8.4", + "version": "1.10.1", "description": "The component used with WordPress to server-side render a preview of dynamic blocks to display in the editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -22,7 +22,7 @@ "module": "build-module/index.js", "react-native": "src/index", "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/api-fetch": "file:../api-fetch", "@wordpress/components": "file:../components", "@wordpress/data": "file:../data", diff --git a/packages/server-side-render/src/server-side-render.js b/packages/server-side-render/src/server-side-render.js index 8e2f93446095d4..f428adf8f4495b 100644 --- a/packages/server-side-render/src/server-side-render.js +++ b/packages/server-side-render/src/server-side-render.js @@ -131,8 +131,8 @@ ServerSideRender.defaultProps = { </Placeholder> ), ErrorResponsePlaceholder: ( { response, className } ) => { - // translators: %s: error message describing the problem const errorMessage = sprintf( + // translators: %s: error message describing the problem __( 'Error loading block: %s' ), response.errorMsg ); diff --git a/packages/shortcode/package.json b/packages/shortcode/package.json index ed8ce524c2f45a..736d144906bdff 100644 --- a/packages/shortcode/package.json +++ b/packages/shortcode/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/shortcode", - "version": "2.6.0", + "version": "2.7.0", "description": "Shortcode module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -21,9 +21,9 @@ "module": "build-module/index.js", "react-native": "src/index", "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "lodash": "^4.17.15", - "memize": "^1.0.5" + "memize": "^1.1.0" }, "publishConfig": { "access": "public" diff --git a/packages/token-list/CHANGELOG.md b/packages/token-list/CHANGELOG.md index 4f09e8ebd8395f..cabfa94ea0427c 100644 --- a/packages/token-list/CHANGELOG.md +++ b/packages/token-list/CHANGELOG.md @@ -1,3 +1,11 @@ +## Master + +## 1.10.0 (2020-04-15) + +### New feature + +- Include TypeScript type declarations ([#18942](https://github.com/WordPress/gutenberg/pull/18942)) + ## 1.1.0 (2018-11-20) ### Enhancements diff --git a/packages/token-list/package.json b/packages/token-list/package.json index 2e7947df9e8f59..45b8e3f34335e7 100644 --- a/packages/token-list/package.json +++ b/packages/token-list/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/token-list", - "version": "1.9.0", + "version": "1.10.0", "description": "Constructable, plain JavaScript DOMTokenList implementation, supporting non-browser runtimes.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -19,8 +19,9 @@ "main": "build/index.js", "module": "build-module/index.js", "react-native": "src/index", + "types": "build-types", "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "lodash": "^4.17.15" }, "publishConfig": { diff --git a/packages/token-list/src/index.js b/packages/token-list/src/index.js index 08f63abfa26128..41f84b47fcc926 100644 --- a/packages/token-list/src/index.js +++ b/packages/token-list/src/index.js @@ -17,11 +17,49 @@ export default class TokenList { constructor( initialValue = '' ) { this.value = initialValue; - [ 'entries', 'forEach', 'keys', 'values' ].forEach( ( fn ) => { - this[ fn ] = ( ...args ) => this._valueAsArray[ fn ]( ...args ); - } ); + // Disable reason: These are type hints on the class. + /* eslint-disable no-unused-expressions */ + /** @type {string} */ + this._currentValue; + + /** @type {string[]} */ + this._valueAsArray; + /* eslint-enable no-unused-expressions */ } + // Disable reason: JSDoc lint doesn't understand TypeScript types + /* eslint-disable jsdoc/valid-types */ + + /** + * @param {Parameters<Array<string>['entries']>} args + */ + entries( ...args ) { + return this._valueAsArray.entries( ...args ); + } + + /** + * @param {Parameters<Array<string>['forEach']>} args + */ + forEach( ...args ) { + return this._valueAsArray.forEach( ...args ); + } + + /** + * @param {Parameters<Array<string>['keys']>} args + */ + keys( ...args ) { + return this._valueAsArray.keys( ...args ); + } + + /** + * @param {Parameters<Array<string>['values']>} args + */ + values( ...args ) { + return this._valueAsArray.values( ...args ); + } + + /* eslint-enable jsdoc/valid-types */ + /** * Returns the associated set as string. * diff --git a/packages/token-list/tsconfig.json b/packages/token-list/tsconfig.json new file mode 100644 index 00000000000000..e22ff86abb6f2d --- /dev/null +++ b/packages/token-list/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "build-types" + }, + "include": [ "src/**/*" ] +} diff --git a/packages/url/CHANGELOG.md b/packages/url/CHANGELOG.md index 2845b6c35e4ac6..177d4fd1c8eda2 100644 --- a/packages/url/CHANGELOG.md +++ b/packages/url/CHANGELOG.md @@ -1,5 +1,13 @@ ## Master +## 2.13.0 (2020-04-15) + +### New feature + +- Include TypeScript type declarations ([#18942](https://github.com/WordPress/gutenberg/pull/18942)) + +# 2.12.0 (2020-04-01) + ### Bug Fixes - `getQueryString` now correctly considers hash fragments when considering whether to return a query string. Previously, `getQueryString( 'https://example.com/#?foo' )` would wrongly return `'foo'` as its result. A hash fragment is always the last segment of a URL, and the querystring must always precede it ([see reference specification](https://url.spec.whatwg.org/#absolute-url-with-fragment-string)). diff --git a/packages/url/README.md b/packages/url/README.md index 71b2a0d47a5ab0..d2b66ef4c71cb6 100644 --- a/packages/url/README.md +++ b/packages/url/README.md @@ -44,11 +44,11 @@ Performs some basic cleanup of a string for use as a post slug. This replicates some of what `sanitize_title()` does in WordPress core, but is only designed to approximate what the slug will be. -Converts whitespace, periods, forward slashes and underscores to hyphens. Converts Latin-1 Supplement and Latin Extended-A letters to basic Latin -letters. Removes combining diacritical marks. Converts remaining string -to lowercase. It does not touch octets, HTML entities, or other encoded -characters. +letters. Removes combining diacritical marks. Converts whitespace, periods, +and forward slashes to hyphens. Removes any remaining non-word characters +except hyphens. Converts remaining string to lowercase. It does not account +for octets, HTML entities, or other encoded characters. _Parameters_ diff --git a/packages/url/package.json b/packages/url/package.json index c564a35d316e11..bdb10d5eb32e35 100644 --- a/packages/url/package.json +++ b/packages/url/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/url", - "version": "2.11.0", + "version": "2.13.0", "description": "WordPress URL utilities.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -20,9 +20,10 @@ "main": "build/index.js", "module": "build-module/index.js", "react-native": "src/index", + "types": "build-types", "sideEffects": false, "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "lodash": "^4.17.15", "qs": "^6.5.2", "react-native-url-polyfill": "^1.1.2" diff --git a/packages/url/src/clean-for-slug.js b/packages/url/src/clean-for-slug.js index 4a1b3317d43dd9..a26587b91bde2a 100644 --- a/packages/url/src/clean-for-slug.js +++ b/packages/url/src/clean-for-slug.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { deburr, toLower, trim } from 'lodash'; +import { deburr, trim } from 'lodash'; /** * Performs some basic cleanup of a string for use as a post slug. @@ -9,11 +9,11 @@ import { deburr, toLower, trim } from 'lodash'; * This replicates some of what `sanitize_title()` does in WordPress core, but * is only designed to approximate what the slug will be. * - * Converts whitespace, periods, forward slashes and underscores to hyphens. * Converts Latin-1 Supplement and Latin Extended-A letters to basic Latin - * letters. Removes combining diacritical marks. Converts remaining string - * to lowercase. It does not touch octets, HTML entities, or other encoded - * characters. + * letters. Removes combining diacritical marks. Converts whitespace, periods, + * and forward slashes to hyphens. Removes any remaining non-word characters + * except hyphens. Converts remaining string to lowercase. It does not account + * for octets, HTML entities, or other encoded characters. * * @param {string} string Title or slug to be processed. * @@ -23,7 +23,11 @@ export function cleanForSlug( string ) { if ( ! string ) { return ''; } - return toLower( - deburr( trim( string.replace( /[\s\./_]+/g, '-' ), '-' ) ) + return trim( + deburr( string ) + .replace( /[\s\./]+/g, '-' ) + .replace( /[^\w-]+/g, '' ) + .toLowerCase(), + '-' ); } diff --git a/packages/url/src/get-query-arg.js b/packages/url/src/get-query-arg.js index 38330aed3ac458..f6e184f0798ce3 100644 --- a/packages/url/src/get-query-arg.js +++ b/packages/url/src/get-query-arg.js @@ -3,9 +3,11 @@ */ import { parse } from 'qs'; +/* eslint-disable jsdoc/valid-types */ /** * @typedef {{[key: string]: QueryArgParsed}} QueryArgObject */ +/* eslint-enable */ /** * @typedef {string|string[]|QueryArgObject} QueryArgParsed diff --git a/packages/url/src/is-url.native.js b/packages/url/src/is-url.native.js index 9a8048a00fa56e..d3b5cd5dd23d0d 100644 --- a/packages/url/src/is-url.native.js +++ b/packages/url/src/is-url.native.js @@ -3,9 +3,11 @@ */ import { URL } from 'react-native-url-polyfill'; +/* eslint-disable jsdoc/valid-types */ /** * @type {typeof import('./is-url').isURL} */ +/* eslint-enable */ export function isURL( url ) { // A URL can be considered value if the `URL` constructor is able to parse // it. The constructor throws an error for an invalid URL. diff --git a/packages/url/src/test/index.test.js b/packages/url/src/test/index.test.js index b9e85c88e748cf..5473ee98eeb483 100644 --- a/packages/url/src/test/index.test.js +++ b/packages/url/src/test/index.test.js @@ -666,7 +666,7 @@ describe( 'filterURLForDisplay', () => { describe( 'cleanForSlug', () => { it( 'should return string prepared for use as url slug', () => { - expect( cleanForSlug( ' /DΓ©jΓ _vu. ' ) ).toBe( 'deja-vu' ); + expect( cleanForSlug( '/Is th@t DΓ©jΓ _vu? ' ) ).toBe( 'is-tht-deja_vu' ); } ); it( 'should return an empty string for missing argument', () => { diff --git a/packages/url/tsconfig.json b/packages/url/tsconfig.json new file mode 100644 index 00000000000000..70efdfe49990d5 --- /dev/null +++ b/packages/url/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "src", + "declarationDir": "build-types", + + // This is required because the `react-native-url-polyfill` dependency lacks types + "noImplicitAny": false + }, + "include": [ "src/**/*" ] +} diff --git a/packages/viewport/package.json b/packages/viewport/package.json index 5e94839df41896..753838a0863f6c 100644 --- a/packages/viewport/package.json +++ b/packages/viewport/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/viewport", - "version": "2.13.1", + "version": "2.15.1", "description": "Viewport module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -21,7 +21,7 @@ "module": "build-module/index.js", "react-native": "src/index", "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "@wordpress/compose": "file:../compose", "@wordpress/data": "file:../data", "lodash": "^4.17.15" diff --git a/packages/warning/CHANGELOG.md b/packages/warning/CHANGELOG.md index 15517d8f1ce7c7..2407c12cf85bf1 100644 --- a/packages/warning/CHANGELOG.md +++ b/packages/warning/CHANGELOG.md @@ -1,5 +1,11 @@ ## Master +## 1.1.0 (2020-04-15) + +### New feature + +- Include TypeScript type declarations ([#18942](https://github.com/WordPress/gutenberg/pull/18942)) + ## 1.0.0 (2020-02-04) Initial release. diff --git a/packages/warning/package.json b/packages/warning/package.json index fd94779db9e83b..a84ecfefadcaad 100644 --- a/packages/warning/package.json +++ b/packages/warning/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/warning", - "version": "1.0.0", + "version": "1.1.0", "description": "Warning utility for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -20,6 +20,7 @@ "main": "build/index.js", "module": "build-module/index.js", "react-native": "src/index", + "types": "build-types", "sideEffects": false, "publishConfig": { "access": "public" diff --git a/packages/warning/tsconfig.json b/packages/warning/tsconfig.json new file mode 100644 index 00000000000000..3c2c31f506f132 --- /dev/null +++ b/packages/warning/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "src", + "declarationDir": "build-types" + }, + "include": [ "src/**/*" ] +} diff --git a/packages/wordcount/package.json b/packages/wordcount/package.json index 1b7dbcbf5bcb46..a24b2e5ba8973e 100644 --- a/packages/wordcount/package.json +++ b/packages/wordcount/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/wordcount", - "version": "2.7.0", + "version": "2.8.0", "description": "WordPress word count utility.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -22,7 +22,7 @@ "react-native": "src/index", "sideEffects": false, "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.9.2", "lodash": "^4.17.15" }, "publishConfig": { diff --git a/phpunit/class-block-context-test.php b/phpunit/class-block-context-test.php new file mode 100644 index 00000000000000..e78f375345aef6 --- /dev/null +++ b/phpunit/class-block-context-test.php @@ -0,0 +1,132 @@ +<?php +/** + * Test block context. + * + * @package Gutenberg + */ + +class Block_Context_Test extends WP_UnitTestCase { + + /** + * Registered block names. + * + * @var string[] + */ + private $registered_block_names = array(); + + /** + * Sets up each test method. + */ + public function setUp() { + global $post; + + parent::setUp(); + + $args = array( + 'post_content' => 'example', + 'post_excerpt' => '', + ); + + $post = $this->factory()->post->create_and_get( $args ); + setup_postdata( $post ); + } + + /** + * Tear down each test method. + */ + public function tearDown() { + parent::tearDown(); + + while ( ! empty( $this->registered_block_names ) ) { + $block_name = array_pop( $this->registered_block_names ); + unregister_block_type( $block_name ); + } + } + + /** + * Registers a block type. + * + * @param string|WP_Block_Type $name Block type name including namespace, or alternatively a + * complete WP_Block_Type instance. In case a WP_Block_Type + * is provided, the $args parameter will be ignored. + * @param array $args { + * Optional. Array of block type arguments. Any arguments may be defined, however the + * ones described below are supported by default. Default empty array. + * + * @type callable $render_callback Callback used to render blocks of this block type. + * } + */ + protected function register_block_type( $name, $args ) { + register_block_type( $name, $args ); + + $this->registered_block_names[] = $name; + } + + /** + * Tests that a block which provides context makes that context available to + * its inner blocks. + */ + function test_provides_block_context() { + $provided_context = array(); + + $this->register_block_type( + 'gutenberg/test-context-provider', + array( + 'attributes' => array( + 'contextWithAssigned' => array( + 'type' => 'number', + ), + 'contextWithDefault' => array( + 'type' => 'number', + 'default' => 0, + ), + 'contextWithoutDefault' => array( + 'type' => 'number', + ), + 'contextNotRequested' => array( + 'type' => 'number', + ), + ), + 'providesContext' => array( + 'gutenberg/contextWithAssigned' => 'contextWithAssigned', + 'gutenberg/contextWithDefault' => 'contextWithDefault', + 'gutenberg/contextWithoutDefault' => 'contextWithoutDefault', + 'gutenberg/contextNotRequested' => 'contextNotRequested', + ), + ) + ); + + $this->register_block_type( + 'gutenberg/test-context-consumer', + array( + 'context' => array( + 'gutenberg/contextWithDefault', + 'gutenberg/contextWithAssigned', + 'gutenberg/contextWithoutDefault', + ), + 'render_callback' => function( $block ) use ( &$provided_context ) { + $provided_context[] = $block->context; + + return ''; + }, + ) + ); + + $parsed_blocks = parse_blocks( + '<!-- wp:gutenberg/test-context-provider {"contextWithAssigned":10} -->' . + '<!-- wp:gutenberg/test-context-consumer /-->' . + '<!-- /wp:gutenberg/test-context-provider -->' + ); + + render_block( $parsed_blocks[0] ); + + $this->assertEquals( + array( + 'gutenberg/contextWithDefault' => 0, + 'gutenberg/contextWithAssigned' => 10, + ), + $provided_context[0] + ); + } + +} diff --git a/phpunit/class-register-block-type-from-metadata-test.php b/phpunit/class-register-block-type-from-metadata-test.php new file mode 100644 index 00000000000000..e039c078d01640 --- /dev/null +++ b/phpunit/class-register-block-type-from-metadata-test.php @@ -0,0 +1,45 @@ +<?php +/** + * Test `register_block_type_from_metadata`. + * + * @package Gutenberg + */ + +class Register_Block_Type_From_Metadata_Test extends WP_UnitTestCase { + /** + * Tests that the function returns false when the `block.json` is not found + * in the WordPress core. + */ + function test_metadata_not_found_in_wordpress_core() { + $result = register_block_type_from_metadata( 'unknown' ); + + $this->assertFalse( $result ); + } + + /** + * Tests that the function returns false when the `block.json` is not found + * in the current directory. + */ + function test_metadata_not_found_in_the_current_directory() { + $result = register_block_type_from_metadata( __DIR__ ); + + $this->assertFalse( $result ); + } + + /** + * Tests that the function returns the registered block when the `block.json` + * is found in the fixtures directory. + */ + function test_block_registers_with_metadata_fixture() { + $result = register_block_type_from_metadata( + __DIR__ . '/fixtures', + array( + 'foo' => 'bar', + ) + ); + + $this->assertInstanceOf( 'WP_Block_Type', $result ); + $this->assertEquals( 'test/block-name', $result->name ); + $this->assertEquals( 'bar', $result->foo ); + } +} diff --git a/phpunit/class-wp-block-test.php b/phpunit/class-wp-block-test.php new file mode 100644 index 00000000000000..242f96f9eb462c --- /dev/null +++ b/phpunit/class-wp-block-test.php @@ -0,0 +1,370 @@ +<?php +/** + * Test WP_Block class. + * + * @package Gutenberg + */ + +class WP_Block_Test extends WP_UnitTestCase { + + /** + * Fake block type registry. + * + * @var WP_Block_Type_Registry + */ + private $registry = null; + + /** + * Set up each test method. + */ + public function setUp() { + parent::setUp(); + + $this->registry = new WP_Block_Type_Registry(); + } + + /** + * Tear down each test method. + */ + public function tearDown() { + parent::tearDown(); + + $this->registry = null; + } + + function test_constructor_assigns_properties_from_parsed_block() { + $this->registry->register( 'core/example', array() ); + + $parsed_blocks = parse_blocks( '<!-- wp:example {"ok":true} -->a<!-- wp:example /-->b<!-- /wp:example -->' ); + $parsed_block = $parsed_blocks[0]; + $context = array(); + $block = new WP_Block( $parsed_block, $context, $this->registry ); + + $this->assertEquals( $parsed_block['blockName'], $block->name ); + $this->assertEquals( $parsed_block['attrs'], $block->attributes ); + $this->assertEquals( $parsed_block['innerContent'], $block->inner_content ); + $this->assertEquals( $parsed_block['innerHTML'], $block->inner_html ); + } + + function test_constructor_assigns_block_type_from_registry() { + $block_type_settings = array( + 'attributes' => array( + 'defaulted' => array( + 'type' => 'number', + 'default' => 10, + ), + ), + ); + $this->registry->register( 'core/example', $block_type_settings ); + + $parsed_block = array( 'blockName' => 'core/example' ); + $context = array(); + $block = new WP_Block( $parsed_block, $context, $this->registry ); + + $this->assertInstanceOf( WP_Block_Type::class, $block->block_type ); + $this->assertEquals( + $block_type_settings['attributes'], + $block->block_type->attributes + ); + } + + function test_constructor_assigns_attributes_with_defaults() { + $this->registry->register( + 'core/example', + array( + 'attributes' => array( + 'defaulted' => array( + 'type' => 'number', + 'default' => 10, + ), + ), + ) + ); + + $parsed_block = array( + 'blockName' => 'core/example', + 'attrs' => array( + 'explicit' => 20, + ), + ); + $context = array(); + $block = new WP_Block( $parsed_block, $context, $this->registry ); + + $this->assertEquals( + array( + 'defaulted' => 10, + 'explicit' => 20, + ), + $block->attributes + ); + } + + function test_constructor_assigns_attributes_with_only_defaults() { + $this->registry->register( + 'core/example', + array( + 'attributes' => array( + 'defaulted' => array( + 'type' => 'number', + 'default' => 10, + ), + ), + ) + ); + + $parsed_block = array( + 'blockName' => 'core/example', + 'attrs' => array(), + ); + $context = array(); + $block = new WP_Block( $parsed_block, $context, $this->registry ); + + $this->assertEquals( array( 'defaulted' => 10 ), $block->attributes ); + } + + function test_constructor_assigns_context_from_block_type() { + $this->registry->register( + 'core/example', + array( + 'context' => array( 'requested' ), + ) + ); + + $parsed_block = array( 'blockName' => 'core/example' ); + $context = array( + 'requested' => 'included', + 'unrequested' => 'not included', + ); + $block = new WP_Block( $parsed_block, $context, $this->registry ); + + $this->assertEquals( array( 'requested' => 'included' ), $block->context ); + } + + function test_constructor_maps_inner_blocks() { + $this->registry->register( 'core/example', array() ); + + $parsed_blocks = parse_blocks( '<!-- wp:example {"ok":true} -->a<!-- wp:example /-->b<!-- /wp:example -->' ); + $parsed_block = $parsed_blocks[0]; + $context = array(); + $block = new WP_Block( $parsed_block, $context, $this->registry ); + + $this->assertCount( 1, $block->inner_blocks ); + $this->assertInstanceOf( WP_Block::class, $block->inner_blocks[0] ); + $this->assertEquals( 'core/example', $block->inner_blocks[0]->name ); + } + + function test_constructor_prepares_context_for_inner_blocks() { + $this->registry->register( + 'core/outer', + array( + 'attributes' => array( + 'recordId' => array( + 'type' => 'number', + ), + ), + 'providesContext' => array( + 'core/recordId' => 'recordId', + ), + ) + ); + $this->registry->register( + 'core/inner', + array( + 'context' => array( 'core/recordId' ), + ) + ); + + $parsed_blocks = parse_blocks( '<!-- wp:outer {"recordId":10} --><!-- wp:inner /--><!-- /wp:outer -->' ); + $parsed_block = $parsed_blocks[0]; + $context = array( 'unrequested' => 'not included' ); + $block = new WP_Block( $parsed_block, $context, $this->registry ); + + $this->assertCount( 0, $block->context ); + $this->assertEquals( + array( 'core/recordId' => 10 ), + $block->inner_blocks[0]->context + ); + } + + function test_constructor_assigns_merged_context() { + $this->registry->register( + 'core/example', + array( + 'attributes' => array( + 'value' => array( + 'type' => array( 'string', 'null' ), + ), + ), + 'providesContext' => array( + 'core/value' => 'value', + ), + 'context' => array( 'core/value' ), + ) + ); + + $parsed_blocks = parse_blocks( + '<!-- wp:example {"value":"merged"} -->' . + '<!-- wp:example {"value":null} -->' . + '<!-- wp:example /-->' . + '<!-- /wp:example -->' . + '<!-- /wp:example -->' + ); + $parsed_block = $parsed_blocks[0]; + $context = array( 'core/value' => 'original' ); + $block = new WP_Block( $parsed_block, $context, $this->registry ); + + $this->assertEquals( + array( 'core/value' => 'original' ), + $block->context + ); + $this->assertEquals( + array( 'core/value' => 'merged' ), + $block->inner_blocks[0]->context + ); + $this->assertEquals( + array( 'core/value' => null ), + $block->inner_blocks[0]->inner_blocks[0]->context + ); + } + + function test_render_static_block_type_returns_own_content() { + $this->registry->register( 'core/static', array() ); + $this->registry->register( + 'core/dynamic', + array( + 'render_callback' => function() { + return 'b'; + }, + ) + ); + + $parsed_blocks = parse_blocks( '<!-- wp:static -->a<!-- wp:dynamic /-->c<!-- /wp:static -->' ); + $parsed_block = $parsed_blocks[0]; + $context = array(); + $block = new WP_Block( $parsed_block, $context, $this->registry ); + + $this->assertSame( 'abc', $block->render() ); + } + + function test_render_passes_instance_to_render_callback() { + $this->registry->register( + 'core/greeting', + array( + 'attributes' => array( + 'toWhom' => array( + 'type' => 'string', + ), + 'punctuation' => array( + 'type' => 'string', + 'default' => '!', + ), + ), + 'render_callback' => function( $block ) { + return sprintf( + 'Hello %s%s', + $block->attributes['toWhom'], + $block->attributes['punctuation'] + ); + }, + ) + ); + + $parsed_blocks = parse_blocks( '<!-- wp:greeting {"toWhom":"world"} /-->' ); + $parsed_block = $parsed_blocks[0]; + $context = array(); + $block = new WP_Block( $parsed_block, $context, $this->registry ); + + $this->assertSame( 'Hello world!', $block->render() ); + } + + function test_passes_attributes_to_render_callback() { + $this->registry->register( + 'core/greeting', + array( + 'attributes' => array( + 'toWhom' => array( + 'type' => 'string', + ), + 'punctuation' => array( + 'type' => 'string', + 'default' => '!', + ), + ), + 'render_callback' => function( $block_attributes ) { + return sprintf( + 'Hello %s%s', + $block_attributes['toWhom'], + $block_attributes['punctuation'] + ); + }, + ) + ); + + $parsed_blocks = parse_blocks( '<!-- wp:greeting {"toWhom":"world"} /-->' ); + $parsed_block = $parsed_blocks[0]; + $context = array(); + $block = new WP_Block( $parsed_block, $context, $this->registry ); + + $this->assertSame( 'Hello world!', $block->render() ); + } + + function test_passes_content_to_render_callback() { + $this->registry->register( + 'core/outer', + array( + 'render_callback' => function( $block, $content ) { + return $content; + }, + ) + ); + $this->registry->register( + 'core/inner', + array( + 'render_callback' => function() { + return 'b'; + }, + ) + ); + + $parsed_blocks = parse_blocks( '<!-- wp:outer -->a<!-- wp:inner /-->c<!-- /wp:outer -->' ); + $parsed_block = $parsed_blocks[0]; + $context = array(); + $block = new WP_Block( $parsed_block, $context, $this->registry ); + + $this->assertSame( 'abc', $block->render() ); + } + + function test_array_access_attributes() { + $this->registry->register( + 'core/example', + array( + 'attributes' => array( + 'value' => array( + 'type' => 'string', + ), + ), + ) + ); + $parsed_block = array( + 'blockName' => 'core/example', + 'attrs' => array( 'value' => 'ok' ), + ); + $context = array(); + $block = new WP_Block( $parsed_block, $context, $this->registry ); + + $this->assertTrue( isset( $block['value'] ) ); + $this->assertFalse( isset( $block['nonsense'] ) ); + $this->assertEquals( 'ok', $block['value'] ); + + $block['value'] = 'changed'; + $this->assertEquals( 'changed', $block['value'] ); + $this->assertEquals( 'changed', $block->attributes['value'] ); + + unset( $block['value'] ); + $this->assertFalse( isset( $block['value'] ) ); + + $block[] = 'invalid, but still supported'; + $this->assertEquals( 'invalid, but still supported', $block[0] ); + } + +} diff --git a/phpunit/fixtures/block.json b/phpunit/fixtures/block.json new file mode 100644 index 00000000000000..3da9b88d722a27 --- /dev/null +++ b/phpunit/fixtures/block.json @@ -0,0 +1,4 @@ +{ + "name": "test/block-name", + "category": "widgets" +} diff --git a/readme.txt b/readme.txt index 3f5bcfa5fe3918..b038cc8dbbd09e 100644 --- a/readme.txt +++ b/readme.txt @@ -1,7 +1,7 @@ === Gutenberg === Contributors: matveb, joen, karmatosed Requires at least: 5.3.0 -Tested up to: 5.3 +Tested up to: 5.4 Stable tag: V.V.V License: GPLv2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html @@ -52,4 +52,4 @@ The four phases of the project are Editing, Customization, Collaboration, and Mu == Changelog == -To read the changelog for Gutenberg 7.7.1, please navigate to the <a href="https://github.com/WordPress/gutenberg/releases/tag/v7.7.1">release page</a>. +To read the changelog for Gutenberg 7.9.1, please navigate to the <a href="https://github.com/WordPress/gutenberg/releases/tag/v7.9.1">release page</a>. diff --git a/storybook/README.md b/storybook/README.md index b397d03c607739..ce1411f259e0f8 100644 --- a/storybook/README.md +++ b/storybook/README.md @@ -7,9 +7,3 @@ The Gutenberg project uses Storybook to view and work with the UI components dev View online at: https://wordpress.github.io/gutenberg/ Run locally in your development environment running: `npm run storybook:dev` from the top-level Gutenberg directory. - -## StoryShots Integration - -> [StoryShots](https://www.npmjs.com/package/@storybook/addon-storyshots) adds automatic Jest Snapshot Testing for [Storybook](https://storybook.js.org/). - -Please refer to [Testing Overview](/docs/contributors/testing-overview.md#storyshots) to learn how to maintain auto-generated unit tests from stories added to Storybook. diff --git a/storybook/test/__snapshots__/index.js.snap b/storybook/test/__snapshots__/index.js.snap deleted file mode 100644 index 1dade55b95dfc2..00000000000000 --- a/storybook/test/__snapshots__/index.js.snap +++ /dev/null @@ -1,16077 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Storyshots Components/Animate Appear Bottom Left 1`] = ` -<div - className="components-animate__appear is-from-left is-from-bottom components-notice is-success is-dismissible" -> - <div - className="components-notice__content" - > - <p> - Appear animation. Origin: - bottom left - . - </p> - </div> - <button - aria-label="Dismiss this notice" - className="components-button components-notice__dismiss has-icon" - onClick={[Function]} - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13 11.8l6.1-6.3-1-1-6.1 6.2-6.1-6.2-1 1 6.1 6.3-6.5 6.7 1 1 6.5-6.6 6.5 6.6 1-1z" - /> - </svg> - </button> -</div> -`; - -exports[`Storyshots Components/Animate Appear Bottom Right 1`] = ` -<div - className="components-animate__appear is-from-right is-from-bottom components-notice is-success is-dismissible" -> - <div - className="components-notice__content" - > - <p> - Appear animation. Origin: - bottom right - . - </p> - </div> - <button - aria-label="Dismiss this notice" - className="components-button components-notice__dismiss has-icon" - onClick={[Function]} - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13 11.8l6.1-6.3-1-1-6.1 6.2-6.1-6.2-1 1 6.1 6.3-6.5 6.7 1 1 6.5-6.6 6.5 6.6 1-1z" - /> - </svg> - </button> -</div> -`; - -exports[`Storyshots Components/Animate Appear Top Left 1`] = ` -<div - className="components-animate__appear is-from-left is-from-top components-notice is-success is-dismissible" -> - <div - className="components-notice__content" - > - <p> - Appear animation. Origin: - top left - . - </p> - </div> - <button - aria-label="Dismiss this notice" - className="components-button components-notice__dismiss has-icon" - onClick={[Function]} - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13 11.8l6.1-6.3-1-1-6.1 6.2-6.1-6.2-1 1 6.1 6.3-6.5 6.7 1 1 6.5-6.6 6.5 6.6 1-1z" - /> - </svg> - </button> -</div> -`; - -exports[`Storyshots Components/Animate Appear Top Right 1`] = ` -<div - className="components-animate__appear is-from-right is-from-top components-notice is-success is-dismissible" -> - <div - className="components-notice__content" - > - <p> - Appear animation. Origin: - top right - . - </p> - </div> - <button - aria-label="Dismiss this notice" - className="components-button components-notice__dismiss has-icon" - onClick={[Function]} - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13 11.8l6.1-6.3-1-1-6.1 6.2-6.1-6.2-1 1 6.1 6.3-6.5 6.7 1 1 6.5-6.6 6.5 6.6 1-1z" - /> - </svg> - </button> -</div> -`; - -exports[`Storyshots Components/Animate Default 1`] = ` -<div - className="components-notice is-success is-dismissible" -> - <div - className="components-notice__content" - > - <p> - No default animation. Use one of type = "appear", "slide-in", or "loading". - </p> - </div> - <button - aria-label="Dismiss this notice" - className="components-button components-notice__dismiss has-icon" - onClick={[Function]} - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13 11.8l6.1-6.3-1-1-6.1 6.2-6.1-6.2-1 1 6.1 6.3-6.5 6.7 1 1 6.5-6.6 6.5 6.6 1-1z" - /> - </svg> - </button> -</div> -`; - -exports[`Storyshots Components/Animate Loading 1`] = ` -<div - className="components-animate__loading components-notice is-success is-dismissible" -> - <div - className="components-notice__content" - > - <p> - Loading animation. - </p> - </div> - <button - aria-label="Dismiss this notice" - className="components-button components-notice__dismiss has-icon" - onClick={[Function]} - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13 11.8l6.1-6.3-1-1-6.1 6.2-6.1-6.2-1 1 6.1 6.3-6.5 6.7 1 1 6.5-6.6 6.5 6.6 1-1z" - /> - </svg> - </button> -</div> -`; - -exports[`Storyshots Components/Animate Slide In 1`] = ` -<div - className="components-animate__slide-in is-from-left components-notice is-success is-dismissible" -> - <div - className="components-notice__content" - > - <p> - Slide-in animation. - </p> - </div> - <button - aria-label="Dismiss this notice" - className="components-button components-notice__dismiss has-icon" - onClick={[Function]} - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13 11.8l6.1-6.3-1-1-6.1 6.2-6.1-6.2-1 1 6.1 6.3-6.5 6.7 1 1 6.5-6.6 6.5 6.6 1-1z" - /> - </svg> - </button> -</div> -`; - -exports[`Storyshots Components/BaseControl Default 1`] = ` -<div - className="components-base-control" -> - <div - className="components-base-control__field" - > - <label - className="components-base-control__label" - htmlFor="textarea-1" - > - Label text - </label> - <textarea - id="textarea-1" - /> - </div> - <p - className="components-base-control__help" - id="textarea-1__help" - > - Help text - </p> -</div> -`; - -exports[`Storyshots Components/Button Buttons 1`] = ` -<div - style={ - Object { - "padding": "20px", - } - } -> - <h2> - Small Buttons - </h2> - <div - className="story-buttons-container" - > - <button - className="components-button is-small" - type="button" - > - Button - </button> - <button - className="components-button is-primary is-small" - type="button" - > - Primary Button - </button> - <button - className="components-button is-secondary is-small" - type="button" - > - Secondary Button - </button> - <button - className="components-button is-small is-tertiary" - type="button" - > - Tertiary Button - </button> - <button - className="components-button is-small has-icon" - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 9v1.5h16V9H4zm12 5.5h4V13h-4v1.5zm-6 0h4V13h-4v1.5zm-6 0h4V13H4v1.5z" - /> - </svg> - </button> - <button - className="components-button is-primary is-small has-icon" - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 9v1.5h16V9H4zm12 5.5h4V13h-4v1.5zm-6 0h4V13h-4v1.5zm-6 0h4V13H4v1.5z" - /> - </svg> - </button> - <button - className="components-button is-secondary is-small has-icon" - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 9v1.5h16V9H4zm12 5.5h4V13h-4v1.5zm-6 0h4V13h-4v1.5zm-6 0h4V13H4v1.5z" - /> - </svg> - </button> - <button - className="components-button is-small is-tertiary has-icon" - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 9v1.5h16V9H4zm12 5.5h4V13h-4v1.5zm-6 0h4V13h-4v1.5zm-6 0h4V13H4v1.5z" - /> - </svg> - </button> - <button - className="components-button is-primary is-small has-text has-icon" - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 9v1.5h16V9H4zm12 5.5h4V13h-4v1.5zm-6 0h4V13h-4v1.5zm-6 0h4V13H4v1.5z" - /> - </svg> - Icon & Text - </button> - </div> - <h2> - Regular Buttons - </h2> - <div - className="story-buttons-container" - > - <button - className="components-button" - type="button" - > - Button - </button> - <button - className="components-button is-primary" - type="button" - > - Primary Button - </button> - <button - className="components-button is-secondary" - type="button" - > - Secondary Button - </button> - <button - className="components-button is-tertiary" - type="button" - > - Tertiary Button - </button> - <button - className="components-button has-icon" - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 9v1.5h16V9H4zm12 5.5h4V13h-4v1.5zm-6 0h4V13h-4v1.5zm-6 0h4V13H4v1.5z" - /> - </svg> - </button> - <button - className="components-button is-primary has-icon" - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 9v1.5h16V9H4zm12 5.5h4V13h-4v1.5zm-6 0h4V13h-4v1.5zm-6 0h4V13H4v1.5z" - /> - </svg> - </button> - <button - className="components-button is-secondary has-icon" - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 9v1.5h16V9H4zm12 5.5h4V13h-4v1.5zm-6 0h4V13h-4v1.5zm-6 0h4V13H4v1.5z" - /> - </svg> - </button> - <button - className="components-button is-tertiary has-icon" - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 9v1.5h16V9H4zm12 5.5h4V13h-4v1.5zm-6 0h4V13h-4v1.5zm-6 0h4V13H4v1.5z" - /> - </svg> - </button> - <button - className="components-button is-primary has-text has-icon" - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 9v1.5h16V9H4zm12 5.5h4V13h-4v1.5zm-6 0h4V13h-4v1.5zm-6 0h4V13H4v1.5z" - /> - </svg> - Icon & Text - </button> - </div> -</div> -`; - -exports[`Storyshots Components/Button Default 1`] = ` -<button - className="components-button" - type="button" -> - Default Button -</button> -`; - -exports[`Storyshots Components/Button Disabled 1`] = ` -<button - className="components-button" - disabled={true} - type="button" -> - Disabled Button -</button> -`; - -exports[`Storyshots Components/Button Disabled Focusable 1`] = ` -<button - aria-disabled={true} - className="components-button" - disabled={false} - onClick={[Function]} - onMouseDown={[Function]} - type="button" -> - Disabled Button -</button> -`; - -exports[`Storyshots Components/Button Disabled Focusable Icon 1`] = ` -<button - aria-disabled={true} - aria-label="More" - className="components-button has-icon" - disabled={false} - onBlur={[Function]} - onClick={[Function]} - onFocus={[Function]} - onMouseDown={[Function]} - onMouseEnter={[Function]} - onMouseLeave={[Function]} - type="button" -> - <svg - aria-hidden="true" - className="dashicon dashicons-ellipsis" - focusable="false" - height={20} - role="img" - viewBox="0 0 20 20" - width={20} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M5 10c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zm12-2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-7 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z" - /> - </svg> -</button> -`; - -exports[`Storyshots Components/Button Disabled Link 1`] = ` -<button - className="components-button" - disabled={true} - type="button" -> - Disabled Link Button -</button> -`; - -exports[`Storyshots Components/Button Grouped Icons 1`] = ` -<div - style={ - Object { - "display": "inline-flex", - } - } -> - <button - aria-label="Bold" - className="components-button has-icon" - onBlur={[Function]} - onClick={[Function]} - onFocus={[Function]} - onMouseDown={[Function]} - onMouseEnter={[Function]} - onMouseLeave={[Function]} - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M14.7 11.3c1-.6 1.5-1.6 1.5-3 0-2.3-1.3-3.4-4-3.4H7v14h5.8c1.4 0 2.5-.3 3.3-1 .8-.7 1.2-1.7 1.2-2.9.1-1.9-.8-3.1-2.6-3.7zm-5.1-4h2.3c.6 0 1.1.1 1.4.4.3.3.5.7.5 1.2s-.2 1-.5 1.2c-.3.3-.8.4-1.4.4H9.6V7.3zm4.6 9c-.4.3-1 .4-1.7.4H9.6v-3.9h2.9c.7 0 1.3.2 1.7.5.4.3.6.8.6 1.5s-.2 1.2-.6 1.5z" - /> - </svg> - </button> - <button - aria-label="Italic" - className="components-button has-icon" - onBlur={[Function]} - onClick={[Function]} - onFocus={[Function]} - onMouseDown={[Function]} - onMouseEnter={[Function]} - onMouseLeave={[Function]} - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M12.5 5L10 19h1.9l2.5-14z" - /> - </svg> - </button> - <button - aria-label="Link" - className="components-button has-icon" - onBlur={[Function]} - onClick={[Function]} - onFocus={[Function]} - onMouseDown={[Function]} - onMouseEnter={[Function]} - onMouseLeave={[Function]} - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M15.6 7.2H14v1.5h1.6c2 0 3.7 1.7 3.7 3.7s-1.7 3.7-3.7 3.7H14v1.5h1.6c2.8 0 5.2-2.3 5.2-5.2 0-2.9-2.3-5.2-5.2-5.2zM4.7 12.4c0-2 1.7-3.7 3.7-3.7H10V7.2H8.4c-2.9 0-5.2 2.3-5.2 5.2 0 2.9 2.3 5.2 5.2 5.2H10v-1.5H8.4c-2 0-3.7-1.7-3.7-3.7zm4.6.9h5.3v-1.5H9.3v1.5z" - /> - </svg> - </button> -</div> -`; - -exports[`Storyshots Components/Button Icon 1`] = ` -<button - aria-label="More" - className="components-button has-icon" - onBlur={[Function]} - onClick={[Function]} - onFocus={[Function]} - onMouseDown={[Function]} - onMouseEnter={[Function]} - onMouseLeave={[Function]} - type="button" -> - <svg - aria-hidden="true" - className="dashicon dashicons-ellipsis" - focusable="false" - height={20} - role="img" - viewBox="0 0 20 20" - width={20} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M5 10c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zm12-2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-7 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z" - /> - </svg> -</button> -`; - -exports[`Storyshots Components/Button Link 1`] = ` -<a - className="components-button" - href="https://wordpress.org/" - target="_blank" -> - Link Button -</a> -`; - -exports[`Storyshots Components/Button Pressed 1`] = ` -<button - aria-pressed={true} - className="components-button is-pressed" - type="button" -> - Pressed Button -</button> -`; - -exports[`Storyshots Components/Button Primary 1`] = ` -<button - className="components-button is-primary" - type="button" -> - Primary Button -</button> -`; - -exports[`Storyshots Components/Button Secondary 1`] = ` -<button - className="components-button is-secondary" - type="button" -> - Secondary Button -</button> -`; - -exports[`Storyshots Components/Button Small 1`] = ` -<button - className="components-button is-small" - type="button" -> - Small Button -</button> -`; - -exports[`Storyshots Components/Button Tertiary 1`] = ` -<button - className="components-button is-tertiary" - type="button" -> - Tertiary Button -</button> -`; - -exports[`Storyshots Components/ButtonGroup Default 1`] = ` -<div - className="components-button-group" - role="group" -> - <button - className="components-button is-primary" - style={ - Object { - "margin": "0 4px", - } - } - type="button" - > - Button 1 - </button> - <button - className="components-button is-primary" - style={ - Object { - "margin": "0 4px", - } - } - type="button" - > - Button 2 - </button> -</div> -`; - -exports[`Storyshots Components/Card Default 1`] = ` -.emotion-6 { - background: #fff; - box-sizing: border-box; - border-radius: 3px; - border: 1px solid #e2e4e7; -} - -.emotion-6.is-borderless { - border: none; -} - -.emotion-6.is-elevated { - box-shadow: 0px 1px 3px 0px rgba( 0,0,0,0.2 ),0px 1px 1px 0px rgba( 0,0,0,0.14 ),0px 2px 1px -1px rgba( 0,0,0,0.12 ); -} - -.emotion-0 { - border-bottom: 1px solid #e2e4e7; - border-top-left-radius: 3px; - border-top-right-radius: 3px; - box-sizing: border-box; -} - -.emotion-0:last-child { - border-bottom: none; -} - -.emotion-0.is-size-large { - padding: 20px 28px; -} - -.emotion-0.is-size-medium { - padding: 12px 20px; -} - -.emotion-0.is-size-small { - padding: 8px 12px; -} - -.emotion-0.is-size-extraSmall { - padding: 4px 8px; -} - -.emotion-0.is-borderless { - border: none; -} - -.emotion-0.is-shady { - background: #f3f4f5; -} - -.emotion-2 { - box-sizing: border-box; -} - -.emotion-2.is-size-large { - padding: 28px; -} - -.emotion-2.is-size-medium { - padding: 20px; -} - -.emotion-2.is-size-small { - padding: 12px; -} - -.emotion-2.is-size-extraSmall { - padding: 8px; -} - -.emotion-2.is-shady { - background: #f3f4f5; -} - -.emotion-4 { - border-top: 1px solid #e2e4e7; - border-bottom-left-radius: 3px; - border-bottom-right-radius: 3px; - box-sizing: border-box; -} - -.emotion-4:first-of-type { - border-top: none; -} - -.emotion-4.is-size-large { - padding: 20px 28px; -} - -.emotion-4.is-size-medium { - padding: 12px 20px; -} - -.emotion-4.is-size-small { - padding: 8px 12px; -} - -.emotion-4.is-size-extraSmall { - padding: 4px 8px; -} - -.emotion-4.is-borderless { - border: none; -} - -.emotion-4.is-shady { - background: #f3f4f5; -} - -<div - className="components-card is-size-medium emotion-6 emotion-7" - style={ - Object { - "width": "360px", - } - } -> - <div - className="components-card__header is-size-medium emotion-0 emotion-1" - > - Header - </div> - <div - className="components-card__body is-size-medium emotion-2 emotion-3" - > - Code is Poetry - </div> - <div - className="components-card__footer is-size-medium emotion-4 emotion-5" - > - Footer - </div> -</div> -`; - -exports[`Storyshots Components/Card/Body Default 1`] = ` -.emotion-2 { - background: #fff; - box-sizing: border-box; - border-radius: 3px; - border: 1px solid #e2e4e7; -} - -.emotion-2.is-borderless { - border: none; -} - -.emotion-2.is-elevated { - box-shadow: 0px 1px 3px 0px rgba( 0,0,0,0.2 ),0px 1px 1px 0px rgba( 0,0,0,0.14 ),0px 2px 1px -1px rgba( 0,0,0,0.12 ); -} - -.emotion-0 { - box-sizing: border-box; -} - -.emotion-0.is-size-large { - padding: 28px; -} - -.emotion-0.is-size-medium { - padding: 20px; -} - -.emotion-0.is-size-small { - padding: 12px; -} - -.emotion-0.is-size-extraSmall { - padding: 8px; -} - -.emotion-0.is-shady { - background: #f3f4f5; -} - -<div - className="components-card is-size-medium emotion-2 emotion-3" - style={ - Object { - "width": "360px", - } - } -> - <div - className="components-card__body is-size-medium emotion-0 emotion-1" - > - Content - </div> -</div> -`; - -exports[`Storyshots Components/Card/Divider Default 1`] = ` -.emotion-6 { - background: #fff; - box-sizing: border-box; - border-radius: 3px; - border: 1px solid #e2e4e7; -} - -.emotion-6.is-borderless { - border: none; -} - -.emotion-6.is-elevated { - box-shadow: 0px 1px 3px 0px rgba( 0,0,0,0.2 ),0px 1px 1px 0px rgba( 0,0,0,0.14 ),0px 2px 1px -1px rgba( 0,0,0,0.12 ); -} - -.emotion-0 { - box-sizing: border-box; -} - -.emotion-0.is-size-large { - padding: 28px; -} - -.emotion-0.is-size-medium { - padding: 20px; -} - -.emotion-0.is-size-small { - padding: 12px; -} - -.emotion-0.is-size-extraSmall { - padding: 8px; -} - -.emotion-0.is-shady { - background: #f3f4f5; -} - -.emotion-2 { - all: unset; - border-top: 1px solid #e2e4e7; - box-sizing: border-box; - display: block; - height: 0; - width: 100%; -} - -<div - className="components-card is-size-medium emotion-6 emotion-7" - style={ - Object { - "width": "360px", - } - } -> - <div - className="components-card__body is-size-medium emotion-0 emotion-1" - > - ... - </div> - <hr - className="components-card__divider emotion-2 emotion-3" - role="separator" - /> - <div - className="components-card__body is-size-medium emotion-0 emotion-1" - > - ... - </div> -</div> -`; - -exports[`Storyshots Components/Card/Footer Default 1`] = ` -.emotion-2 { - background: #fff; - box-sizing: border-box; - border-radius: 3px; - border: 1px solid #e2e4e7; -} - -.emotion-2.is-borderless { - border: none; -} - -.emotion-2.is-elevated { - box-shadow: 0px 1px 3px 0px rgba( 0,0,0,0.2 ),0px 1px 1px 0px rgba( 0,0,0,0.14 ),0px 2px 1px -1px rgba( 0,0,0,0.12 ); -} - -.emotion-0 { - border-top: 1px solid #e2e4e7; - border-bottom-left-radius: 3px; - border-bottom-right-radius: 3px; - box-sizing: border-box; -} - -.emotion-0:first-of-type { - border-top: none; -} - -.emotion-0.is-size-large { - padding: 20px 28px; -} - -.emotion-0.is-size-medium { - padding: 12px 20px; -} - -.emotion-0.is-size-small { - padding: 8px 12px; -} - -.emotion-0.is-size-extraSmall { - padding: 4px 8px; -} - -.emotion-0.is-borderless { - border: none; -} - -.emotion-0.is-shady { - background: #f3f4f5; -} - -<div - className="components-card is-size-medium emotion-2 emotion-3" - style={ - Object { - "width": "360px", - } - } -> - <div - className="components-card__footer is-size-medium emotion-0 emotion-1" - > - Content - </div> -</div> -`; - -exports[`Storyshots Components/Card/Header Default 1`] = ` -.emotion-2 { - background: #fff; - box-sizing: border-box; - border-radius: 3px; - border: 1px solid #e2e4e7; -} - -.emotion-2.is-borderless { - border: none; -} - -.emotion-2.is-elevated { - box-shadow: 0px 1px 3px 0px rgba( 0,0,0,0.2 ),0px 1px 1px 0px rgba( 0,0,0,0.14 ),0px 2px 1px -1px rgba( 0,0,0,0.12 ); -} - -.emotion-0 { - border-bottom: 1px solid #e2e4e7; - border-top-left-radius: 3px; - border-top-right-radius: 3px; - box-sizing: border-box; -} - -.emotion-0:last-child { - border-bottom: none; -} - -.emotion-0.is-size-large { - padding: 20px 28px; -} - -.emotion-0.is-size-medium { - padding: 12px 20px; -} - -.emotion-0.is-size-small { - padding: 8px 12px; -} - -.emotion-0.is-size-extraSmall { - padding: 4px 8px; -} - -.emotion-0.is-borderless { - border: none; -} - -.emotion-0.is-shady { - background: #f3f4f5; -} - -<div - className="components-card is-size-medium emotion-2 emotion-3" - style={ - Object { - "width": "360px", - } - } -> - <div - className="components-card__header is-size-medium emotion-0 emotion-1" - > - Content - </div> -</div> -`; - -exports[`Storyshots Components/Card/Media Default 1`] = ` -.emotion-4 { - background: #fff; - box-sizing: border-box; - border-radius: 3px; - border: 1px solid #e2e4e7; -} - -.emotion-4.is-borderless { - border: none; -} - -.emotion-4.is-elevated { - box-shadow: 0px 1px 3px 0px rgba( 0,0,0,0.2 ),0px 1px 1px 0px rgba( 0,0,0,0.14 ),0px 2px 1px -1px rgba( 0,0,0,0.12 ); -} - -.emotion-2 { - box-sizing: border-box; -} - -.emotion-2.is-size-large { - padding: 28px; -} - -.emotion-2.is-size-medium { - padding: 20px; -} - -.emotion-2.is-size-small { - padding: 12px; -} - -.emotion-2.is-size-extraSmall { - padding: 8px; -} - -.emotion-2.is-shady { - background: #f3f4f5; -} - -.emotion-0 { - box-sizing: border-box; - overflow: hidden; -} - -.emotion-0 > img, -.emotion-0 > iframe { - display: block; - height: auto; - max-width: 100%; - width: 100%; -} - -.emotion-0:first-of-type { - border-top-left-radius: 3px; - border-top-right-radius: 3px; -} - -.emotion-0:last-of-type { - border-bottom-left-radius: 3px; - border-bottom-right-radius: 3px; -} - -<div - className="components-card is-size-medium emotion-4 emotion-5" - style={ - Object { - "width": "360px", - } - } -> - <div - className="components-card__media emotion-0 emotion-1" - > - <img - alt="SMELLING MARSHMELLOW ICECREAM CONE" - src="https://images.unsplash.com/photo-1570776765652-4ce2a88cc1f9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80" - /> - </div> - <div - className="components-card__body is-size-medium emotion-2 emotion-3" - > - Content - </div> -</div> -`; - -exports[`Storyshots Components/Card/Media Header And Footer 1`] = ` -.emotion-6 { - background: #fff; - box-sizing: border-box; - border-radius: 3px; - border: 1px solid #e2e4e7; -} - -.emotion-6.is-borderless { - border: none; -} - -.emotion-6.is-elevated { - box-shadow: 0px 1px 3px 0px rgba( 0,0,0,0.2 ),0px 1px 1px 0px rgba( 0,0,0,0.14 ),0px 2px 1px -1px rgba( 0,0,0,0.12 ); -} - -.emotion-0 { - border-bottom: 1px solid #e2e4e7; - border-top-left-radius: 3px; - border-top-right-radius: 3px; - box-sizing: border-box; -} - -.emotion-0:last-child { - border-bottom: none; -} - -.emotion-0.is-size-large { - padding: 20px 28px; -} - -.emotion-0.is-size-medium { - padding: 12px 20px; -} - -.emotion-0.is-size-small { - padding: 8px 12px; -} - -.emotion-0.is-size-extraSmall { - padding: 4px 8px; -} - -.emotion-0.is-borderless { - border: none; -} - -.emotion-0.is-shady { - background: #f3f4f5; -} - -.emotion-4 { - border-top: 1px solid #e2e4e7; - border-bottom-left-radius: 3px; - border-bottom-right-radius: 3px; - box-sizing: border-box; -} - -.emotion-4:first-of-type { - border-top: none; -} - -.emotion-4.is-size-large { - padding: 20px 28px; -} - -.emotion-4.is-size-medium { - padding: 12px 20px; -} - -.emotion-4.is-size-small { - padding: 8px 12px; -} - -.emotion-4.is-size-extraSmall { - padding: 4px 8px; -} - -.emotion-4.is-borderless { - border: none; -} - -.emotion-4.is-shady { - background: #f3f4f5; -} - -.emotion-2 { - box-sizing: border-box; - overflow: hidden; -} - -.emotion-2 > img, -.emotion-2 > iframe { - display: block; - height: auto; - max-width: 100%; - width: 100%; -} - -.emotion-2:first-of-type { - border-top-left-radius: 3px; - border-top-right-radius: 3px; -} - -.emotion-2:last-of-type { - border-bottom-left-radius: 3px; - border-bottom-right-radius: 3px; -} - -<div - className="components-card is-size-medium emotion-6 emotion-7" - style={ - Object { - "width": "360px", - } - } -> - <div - className="components-card__header is-size-medium emotion-0 emotion-1" - > - Header Content - </div> - <div - className="components-card__media emotion-2 emotion-3" - > - <img - alt="SMELLING MARSHMELLOW ICECREAM CONE" - src="https://images.unsplash.com/photo-1570776765652-4ce2a88cc1f9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80" - /> - </div> - <div - className="components-card__footer is-shady is-size-medium emotion-4 emotion-5" - > - Caption - </div> -</div> -`; - -exports[`Storyshots Components/Card/Media Horizontally Aligned 1`] = ` -Array [ - <p> - Note: This story demonstrates how this UI may be created. It requires extra styling. - </p>, - .emotion-7 { - background: #fff; - box-sizing: border-box; - border-radius: 3px; - border: 1px solid #e2e4e7; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; -} - -.emotion-7.is-borderless { - border: none; -} - -.emotion-7.is-elevated { - box-shadow: 0px 1px 3px 0px rgba( 0,0,0,0.2 ),0px 1px 1px 0px rgba( 0,0,0,0.14 ),0px 2px 1px -1px rgba( 0,0,0,0.12 ); -} - -.emotion-7.is-right { - -webkit-flex-direction: row-reverse; - -ms-flex-direction: row-reverse; - flex-direction: row-reverse; -} - -.emotion-7 .emotion-3 { - -webkit-flex: 1; - -ms-flex: 1; - flex: 1; -} - -.emotion-7 .emotion-0.is-left { - border-radius: 3px 0 0 3px; -} - -.emotion-7 .emotion-0.is-right { - border-radius: 0 3px 3px 0; -} - -.emotion-1 { - box-sizing: border-box; - overflow: hidden; -} - -.emotion-1 > img, -.emotion-1 > iframe { - display: block; - height: auto; - max-width: 100%; - width: 100%; -} - -.emotion-1:first-of-type { - border-top-left-radius: 3px; - border-top-right-radius: 3px; -} - -.emotion-1:last-of-type { - border-bottom-left-radius: 3px; - border-bottom-right-radius: 3px; -} - -.emotion-4 { - box-sizing: border-box; -} - -.emotion-4.is-size-large { - padding: 28px; -} - -.emotion-4.is-size-medium { - padding: 20px; -} - -.emotion-4.is-size-small { - padding: 12px; -} - -.emotion-4.is-size-extraSmall { - padding: 8px; -} - -.emotion-4.is-shady { - background: #f3f4f5; -} - -<div - className="components-card is-size-medium is-left emotion-6 emotion-7 emotion-8" - > - <div - className="components-card__media is-left emotion-0 emotion-1 emotion-2" - style={ - Object { - "maxWidth": 200, - } - } - > - <img - alt="SMELLING MARSHMELLOW ICECREAM CONE" - src="https://images.unsplash.com/photo-1570776765652-4ce2a88cc1f9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80" - /> - </div> - <div - className="components-card__body is-size-medium emotion-3 emotion-4 emotion-5" - > - Content - </div> - </div>, -] -`; - -exports[`Storyshots Components/Card/Media Iframe Embed 1`] = ` -.emotion-4 { - background: #fff; - box-sizing: border-box; - border-radius: 3px; - border: 1px solid #e2e4e7; -} - -.emotion-4.is-borderless { - border: none; -} - -.emotion-4.is-elevated { - box-shadow: 0px 1px 3px 0px rgba( 0,0,0,0.2 ),0px 1px 1px 0px rgba( 0,0,0,0.14 ),0px 2px 1px -1px rgba( 0,0,0,0.12 ); -} - -.emotion-0 { - border-bottom: 1px solid #e2e4e7; - border-top-left-radius: 3px; - border-top-right-radius: 3px; - box-sizing: border-box; -} - -.emotion-0:last-child { - border-bottom: none; -} - -.emotion-0.is-size-large { - padding: 20px 28px; -} - -.emotion-0.is-size-medium { - padding: 12px 20px; -} - -.emotion-0.is-size-small { - padding: 8px 12px; -} - -.emotion-0.is-size-extraSmall { - padding: 4px 8px; -} - -.emotion-0.is-borderless { - border: none; -} - -.emotion-0.is-shady { - background: #f3f4f5; -} - -.emotion-2 { - box-sizing: border-box; - overflow: hidden; -} - -.emotion-2 > img, -.emotion-2 > iframe { - display: block; - height: auto; - max-width: 100%; - width: 100%; -} - -.emotion-2:first-of-type { - border-top-left-radius: 3px; - border-top-right-radius: 3px; -} - -.emotion-2:last-of-type { - border-bottom-left-radius: 3px; - border-bottom-right-radius: 3px; -} - -<div - className="components-card is-size-medium emotion-4 emotion-5" - style={ - Object { - "width": "360px", - } - } -> - <div - className="components-card__header is-size-medium emotion-0 emotion-1" - > - Header Content - </div> - <div - className="components-card__media emotion-2 emotion-3" - > - <iframe - allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" - allowFullScreen={true} - frameBorder="0" - height="315" - src="https://www.youtube.com/embed/zGP6zk7jcrQ" - title="Corgi" - width="560" - /> - </div> -</div> -`; - -exports[`Storyshots Components/Card/Media On Bottom 1`] = ` -.emotion-4 { - background: #fff; - box-sizing: border-box; - border-radius: 3px; - border: 1px solid #e2e4e7; -} - -.emotion-4.is-borderless { - border: none; -} - -.emotion-4.is-elevated { - box-shadow: 0px 1px 3px 0px rgba( 0,0,0,0.2 ),0px 1px 1px 0px rgba( 0,0,0,0.14 ),0px 2px 1px -1px rgba( 0,0,0,0.12 ); -} - -.emotion-0 { - box-sizing: border-box; -} - -.emotion-0.is-size-large { - padding: 28px; -} - -.emotion-0.is-size-medium { - padding: 20px; -} - -.emotion-0.is-size-small { - padding: 12px; -} - -.emotion-0.is-size-extraSmall { - padding: 8px; -} - -.emotion-0.is-shady { - background: #f3f4f5; -} - -.emotion-2 { - box-sizing: border-box; - overflow: hidden; -} - -.emotion-2 > img, -.emotion-2 > iframe { - display: block; - height: auto; - max-width: 100%; - width: 100%; -} - -.emotion-2:first-of-type { - border-top-left-radius: 3px; - border-top-right-radius: 3px; -} - -.emotion-2:last-of-type { - border-bottom-left-radius: 3px; - border-bottom-right-radius: 3px; -} - -<div - className="components-card is-size-medium emotion-4 emotion-5" - style={ - Object { - "width": "360px", - } - } -> - <div - className="components-card__body is-size-medium emotion-0 emotion-1" - > - Content - </div> - <div - className="components-card__media emotion-2 emotion-3" - > - <img - alt="SMELLING MARSHMELLOW ICECREAM CONE" - src="https://images.unsplash.com/photo-1570776765652-4ce2a88cc1f9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80" - /> - </div> -</div> -`; - -exports[`Storyshots Components/Card/Media On Top 1`] = ` -.emotion-4 { - background: #fff; - box-sizing: border-box; - border-radius: 3px; - border: 1px solid #e2e4e7; -} - -.emotion-4.is-borderless { - border: none; -} - -.emotion-4.is-elevated { - box-shadow: 0px 1px 3px 0px rgba( 0,0,0,0.2 ),0px 1px 1px 0px rgba( 0,0,0,0.14 ),0px 2px 1px -1px rgba( 0,0,0,0.12 ); -} - -.emotion-2 { - box-sizing: border-box; -} - -.emotion-2.is-size-large { - padding: 28px; -} - -.emotion-2.is-size-medium { - padding: 20px; -} - -.emotion-2.is-size-small { - padding: 12px; -} - -.emotion-2.is-size-extraSmall { - padding: 8px; -} - -.emotion-2.is-shady { - background: #f3f4f5; -} - -.emotion-0 { - box-sizing: border-box; - overflow: hidden; -} - -.emotion-0 > img, -.emotion-0 > iframe { - display: block; - height: auto; - max-width: 100%; - width: 100%; -} - -.emotion-0:first-of-type { - border-top-left-radius: 3px; - border-top-right-radius: 3px; -} - -.emotion-0:last-of-type { - border-bottom-left-radius: 3px; - border-bottom-right-radius: 3px; -} - -<div - className="components-card is-size-medium emotion-4 emotion-5" - style={ - Object { - "width": "360px", - } - } -> - <div - className="components-card__media emotion-0 emotion-1" - > - <img - alt="SMELLING MARSHMELLOW ICECREAM CONE" - src="https://images.unsplash.com/photo-1570776765652-4ce2a88cc1f9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80" - /> - </div> - <div - className="components-card__body is-size-medium emotion-2 emotion-3" - > - <div> - Content - </div> - </div> -</div> -`; - -exports[`Storyshots Components/CheckboxControl All 1`] = ` -<div - className="components-base-control" -> - <div - className="components-base-control__field" - > - <label - className="components-base-control__label" - htmlFor="inspector-checkbox-control-1" - > - User - </label> - <span - className="components-checkbox-control__input-container" - > - <input - aria-describedby="inspector-checkbox-control-1__help" - checked={true} - className="components-checkbox-control__input" - id="inspector-checkbox-control-1" - onChange={[Function]} - type="checkbox" - value="1" - /> - <svg - aria-hidden="true" - className="components-checkbox-control__checked" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9 18.6L3.5 13l1-1L9 16.4l9.5-9.9 1 1z" - /> - </svg> - </span> - <label - className="components-checkbox-control__label" - htmlFor="inspector-checkbox-control-1" - > - Is author - </label> - </div> - <p - className="components-base-control__help" - id="inspector-checkbox-control-1__help" - > - Is the user an author or not? - </p> -</div> -`; - -exports[`Storyshots Components/CheckboxControl Default 1`] = ` -<div - className="components-base-control" -> - <div - className="components-base-control__field" - > - <span - className="components-checkbox-control__input-container" - > - <input - checked={true} - className="components-checkbox-control__input" - id="inspector-checkbox-control-0" - onChange={[Function]} - type="checkbox" - value="1" - /> - <svg - aria-hidden="true" - className="components-checkbox-control__checked" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9 18.6L3.5 13l1-1L9 16.4l9.5-9.9 1 1z" - /> - </svg> - </span> - <label - className="components-checkbox-control__label" - htmlFor="inspector-checkbox-control-0" - > - Is author - </label> - </div> -</div> -`; - -exports[`Storyshots Components/ClipboardButton Default 1`] = ` -<span - onCopy={[Function]} -> - <button - className="components-button components-clipboard-button is-primary" - type="button" - > - Copy "Text" - </button> -</span> -`; - -exports[`Storyshots Components/ColorIndicator Default 1`] = ` -<span - className="component-color-indicator" - style={ - Object { - "background": "#0073aa", - } - } -/> -`; - -exports[`Storyshots Components/ColorPalette Default 1`] = ` -<div - className="components-circular-option-picker" -> - <div - className="components-circular-option-picker__option-wrapper" - > - <button - aria-label="Color: red" - aria-pressed={false} - className="components-button components-circular-option-picker__option" - onBlur={[Function]} - onClick={[Function]} - onFocus={[Function]} - onMouseDown={[Function]} - onMouseEnter={[Function]} - onMouseLeave={[Function]} - style={ - Object { - "backgroundColor": "#f00", - "color": "#f00", - } - } - type="button" - /> - </div> - <div - className="components-circular-option-picker__option-wrapper" - > - <button - aria-label="Color: white" - aria-pressed={false} - className="components-button components-circular-option-picker__option" - onBlur={[Function]} - onClick={[Function]} - onFocus={[Function]} - onMouseDown={[Function]} - onMouseEnter={[Function]} - onMouseLeave={[Function]} - style={ - Object { - "backgroundColor": "#fff", - "color": "#fff", - } - } - type="button" - /> - </div> - <div - className="components-circular-option-picker__option-wrapper" - > - <button - aria-label="Color: blue" - aria-pressed={false} - className="components-button components-circular-option-picker__option" - onBlur={[Function]} - onClick={[Function]} - onFocus={[Function]} - onMouseDown={[Function]} - onMouseEnter={[Function]} - onMouseLeave={[Function]} - style={ - Object { - "backgroundColor": "#00f", - "color": "#00f", - } - } - type="button" - /> - </div> - <div - className="components-circular-option-picker__custom-clear-wrapper" - > - <div - className="components-dropdown components-circular-option-picker__dropdown-link-action" - > - <button - aria-expanded={false} - aria-label="Custom color picker" - className="components-button is-link" - onClick={[Function]} - type="button" - > - Custom color - </button> - </div> - <button - className="components-button components-circular-option-picker__clear is-secondary is-small" - onClick={[Function]} - type="button" - > - Clear - </button> - </div> -</div> -`; - -exports[`Storyshots Components/ColorPalette With Knobs 1`] = ` -<div - className="components-circular-option-picker" -> - <div - className="components-circular-option-picker__option-wrapper" - > - <button - aria-label="Color: red" - aria-pressed={false} - className="components-button components-circular-option-picker__option" - onBlur={[Function]} - onClick={[Function]} - onFocus={[Function]} - onMouseDown={[Function]} - onMouseEnter={[Function]} - onMouseLeave={[Function]} - style={ - Object { - "backgroundColor": "#f00", - "color": "#f00", - } - } - type="button" - /> - </div> - <div - className="components-circular-option-picker__option-wrapper" - > - <button - aria-label="Color: white" - aria-pressed={false} - className="components-button components-circular-option-picker__option" - onBlur={[Function]} - onClick={[Function]} - onFocus={[Function]} - onMouseDown={[Function]} - onMouseEnter={[Function]} - onMouseLeave={[Function]} - style={ - Object { - "backgroundColor": "#fff", - "color": "#fff", - } - } - type="button" - /> - </div> - <div - className="components-circular-option-picker__option-wrapper" - > - <button - aria-label="Color: blue" - aria-pressed={false} - className="components-button components-circular-option-picker__option" - onBlur={[Function]} - onClick={[Function]} - onFocus={[Function]} - onMouseDown={[Function]} - onMouseEnter={[Function]} - onMouseLeave={[Function]} - style={ - Object { - "backgroundColor": "#00f", - "color": "#00f", - } - } - type="button" - /> - </div> - <div - className="components-circular-option-picker__custom-clear-wrapper" - > - <div - className="components-dropdown components-circular-option-picker__dropdown-link-action" - > - <button - aria-expanded={false} - aria-label="Custom color picker" - className="components-button is-link" - onClick={[Function]} - type="button" - > - Custom color - </button> - </div> - <button - className="components-button components-circular-option-picker__clear is-secondary is-small" - onClick={[Function]} - type="button" - > - Clear - </button> - </div> -</div> -`; - -exports[`Storyshots Components/ColorPicker Alpha Enabled 1`] = ` -<div - className="components-color-picker is-alpha-enabled" -> - <div - className="components-color-picker__saturation" - > - <div> - <div - className="components-color-picker__saturation-color" - onMouseDown={[Function]} - onTouchMove={[Function]} - onTouchStart={[Function]} - role="application" - style={ - Object { - "background": "hsl(0,100%, 50%)", - } - } - > - <div - className="components-color-picker__saturation-white" - /> - <div - className="components-color-picker__saturation-black" - /> - <button - aria-describedby="color-picker-saturation-1" - aria-label="Choose a shade" - className="components-button components-color-picker__saturation-pointer" - onKeyDown={[Function]} - style={ - Object { - "left": "100%", - "top": "0%", - } - } - type="button" - /> - <div - className="components-visually-hidden" - id="color-picker-saturation-1" - > - Use your arrow keys to change the base color. Move up to lighten the color, down to darken, left to decrease saturation, and right to increase saturation. - </div> - </div> - </div> - </div> - <div - className="components-color-picker__body" - > - <div - className="components-color-picker__controls" - > - <div - className="components-color-picker__swatch" - > - <div - className="components-color-picker__active" - style={ - Object { - "backgroundColor": "rgb(255, 0, 0)", - } - } - /> - </div> - <div - className="components-color-picker__toggles" - > - <div> - <div - className="components-color-picker__hue" - > - <div - className="components-color-picker__hue-gradient" - /> - <div - className="components-color-picker__hue-bar" - onMouseDown={[Function]} - onTouchMove={[Function]} - onTouchStart={[Function]} - > - <div - aria-describedby="components-color-picker__hue-description-1" - aria-label="Hue value in degrees, from 0 to 359." - aria-orientation="horizontal" - aria-valuemax="1" - aria-valuemin="359" - aria-valuenow={0} - className="components-color-picker__hue-pointer" - onKeyDown={[Function]} - role="slider" - style={ - Object { - "left": "0%", - } - } - tabIndex="0" - /> - <p - className="components-visually-hidden" - id="components-color-picker__hue-description-1" - > - Move the arrow left or right to change hue. - </p> - </div> - </div> - </div> - <div> - <div - className="components-color-picker__alpha" - > - <div - className="components-color-picker__alpha-gradient" - style={ - Object { - "background": "linear-gradient(to right, rgba(255,0,0, 0) 0%, rgba(255,0,0, 1) 100%)", - } - } - /> - <div - className="components-color-picker__alpha-bar" - onMouseDown={[Function]} - onTouchMove={[Function]} - onTouchStart={[Function]} - > - <div - aria-label="Alpha value, from 0 (transparent) to 1 (fully opaque)." - aria-orientation="horizontal" - aria-valuemax="1" - aria-valuemin="0" - aria-valuenow={1} - className="components-color-picker__alpha-pointer" - onKeyDown={[Function]} - role="slider" - style={ - Object { - "left": "100%", - } - } - tabIndex="0" - /> - </div> - </div> - </div> - </div> - </div> - <div - className="components-color-picker__inputs-wrapper" - > - <div - className="components-color-picker__inputs-fields" - > - <div - className="components-base-control components-color-picker__inputs-field" - > - <div - className="components-base-control__field" - > - <label - className="components-base-control__label" - htmlFor="inspector-text-control-1" - > - Color value in hexadecimal - </label> - <input - className="components-text-control__input" - id="inspector-text-control-1" - onBlur={[Function]} - onChange={[Function]} - onKeyDown={[Function]} - type="text" - value="#ff0000" - /> - </div> - </div> - </div> - <div - className="components-color-picker__inputs-toggle-wrapper" - > - <button - aria-label="Change color format" - className="components-button components-color-picker__inputs-toggle has-icon" - onBlur={[Function]} - onClick={[Function]} - onFocus={[Function]} - onMouseDown={[Function]} - onMouseEnter={[Function]} - onMouseLeave={[Function]} - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M17 9.4L12 14 7 9.4l-1 1.2 6 5.4 6-5.4z" - /> - </svg> - </button> - </div> - </div> - </div> -</div> -`; - -exports[`Storyshots Components/ColorPicker Default 1`] = ` -<div - className="components-color-picker is-alpha-disabled" -> - <div - className="components-color-picker__saturation" - > - <div> - <div - className="components-color-picker__saturation-color" - onMouseDown={[Function]} - onTouchMove={[Function]} - onTouchStart={[Function]} - role="application" - style={ - Object { - "background": "hsl(0,100%, 50%)", - } - } - > - <div - className="components-color-picker__saturation-white" - /> - <div - className="components-color-picker__saturation-black" - /> - <button - aria-describedby="color-picker-saturation-0" - aria-label="Choose a shade" - className="components-button components-color-picker__saturation-pointer" - onKeyDown={[Function]} - style={ - Object { - "left": "100%", - "top": "0%", - } - } - type="button" - /> - <div - className="components-visually-hidden" - id="color-picker-saturation-0" - > - Use your arrow keys to change the base color. Move up to lighten the color, down to darken, left to decrease saturation, and right to increase saturation. - </div> - </div> - </div> - </div> - <div - className="components-color-picker__body" - > - <div - className="components-color-picker__controls" - > - <div - className="components-color-picker__swatch" - > - <div - className="components-color-picker__active" - style={ - Object { - "backgroundColor": "rgb(255, 0, 0)", - } - } - /> - </div> - <div - className="components-color-picker__toggles" - > - <div> - <div - className="components-color-picker__hue" - > - <div - className="components-color-picker__hue-gradient" - /> - <div - className="components-color-picker__hue-bar" - onMouseDown={[Function]} - onTouchMove={[Function]} - onTouchStart={[Function]} - > - <div - aria-describedby="components-color-picker__hue-description-0" - aria-label="Hue value in degrees, from 0 to 359." - aria-orientation="horizontal" - aria-valuemax="1" - aria-valuemin="359" - aria-valuenow={0} - className="components-color-picker__hue-pointer" - onKeyDown={[Function]} - role="slider" - style={ - Object { - "left": "0%", - } - } - tabIndex="0" - /> - <p - className="components-visually-hidden" - id="components-color-picker__hue-description-0" - > - Move the arrow left or right to change hue. - </p> - </div> - </div> - </div> - </div> - </div> - <div - className="components-color-picker__inputs-wrapper" - > - <div - className="components-color-picker__inputs-fields" - > - <div - className="components-base-control components-color-picker__inputs-field" - > - <div - className="components-base-control__field" - > - <label - className="components-base-control__label" - htmlFor="inspector-text-control-0" - > - Color value in hexadecimal - </label> - <input - className="components-text-control__input" - id="inspector-text-control-0" - onBlur={[Function]} - onChange={[Function]} - onKeyDown={[Function]} - type="text" - value="#ff0000" - /> - </div> - </div> - </div> - <div - className="components-color-picker__inputs-toggle-wrapper" - > - <button - aria-label="Change color format" - className="components-button components-color-picker__inputs-toggle has-icon" - onBlur={[Function]} - onClick={[Function]} - onFocus={[Function]} - onMouseDown={[Function]} - onMouseEnter={[Function]} - onMouseLeave={[Function]} - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M17 9.4L12 14 7 9.4l-1 1.2 6 5.4 6-5.4z" - /> - </svg> - </button> - </div> - </div> - </div> -</div> -`; - -exports[`Storyshots Components/CustomSelectControl Default 1`] = ` -<div - className="components-custom-select-control" -> - <label - className="components-custom-select-control__label" - htmlFor="downshift-null-toggle-button" - id="downshift-null-label" - > - Font size - </label> - <button - aria-expanded={false} - aria-haspopup="listbox" - aria-label="Font size" - className="components-button components-custom-select-control__button is-small" - id="downshift-null-toggle-button" - onClick={[Function]} - onKeyDown={[Function]} - type="button" - > - <svg - aria-hidden="true" - className="components-custom-select-control__button-icon" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M17 9.4L12 14 7 9.4l-1 1.2 6 5.4 6-5.4z" - /> - </svg> - </button> - <ul - aria-labelledby="downshift-null-label" - className="components-custom-select-control__menu" - id="downshift-null-menu" - onBlur={[Function]} - onKeyDown={[Function]} - onMouseLeave={[Function]} - role="listbox" - tabIndex={-1} - /> -</div> -`; - -exports[`Storyshots Components/Dashicon Default 1`] = ` -<svg - aria-hidden="true" - className="dashicon dashicons-wordpress" - color="#0079AA" - focusable="false" - height={20} - role="img" - viewBox="0 0 20 20" - width={20} - xmlns="http://www.w3.org/2000/svg" -> - <path - d="M20 10c0-5.52-4.48-10-10-10S0 4.48 0 10s4.48 10 10 10 10-4.48 10-10zM10 1.01c4.97 0 8.99 4.02 8.99 8.99s-4.02 8.99-8.99 8.99S1.01 14.97 1.01 10 5.03 1.01 10 1.01zM8.01 14.82L4.96 6.61c.49-.03 1.05-.08 1.05-.08.43-.05.38-1.01-.06-.99 0 0-1.29.1-2.13.1-.15 0-.33 0-.52-.01 1.44-2.17 3.9-3.6 6.7-3.6 2.09 0 3.99.79 5.41 2.09-.6-.08-1.45.35-1.45 1.42 0 .66.38 1.22.79 1.88.31.54.5 1.22.5 2.21 0 1.34-1.27 4.48-1.27 4.48l-2.71-7.5c.48-.03.75-.16.75-.16.43-.05.38-1.1-.05-1.08 0 0-1.3.11-2.14.11-.78 0-2.11-.11-2.11-.11-.43-.02-.48 1.06-.05 1.08l.84.08 1.12 3.04zm6.02 2.15L16.64 10s.67-1.69.39-3.81c.63 1.14.94 2.42.94 3.81 0 2.96-1.56 5.58-3.94 6.97zM2.68 6.77L6.5 17.25c-2.67-1.3-4.47-4.08-4.47-7.25 0-1.16.2-2.23.65-3.23zm7.45 4.53l2.29 6.25c-.75.27-1.57.42-2.42.42-.72 0-1.41-.11-2.06-.3z" - /> -</svg> -`; - -exports[`Storyshots Components/Draggable Default 1`] = ` -<div> - <p> - Is Dragging? - No - </p> - <div - id="draggable-example-box" - style={ - Object { - "display": "inline-flex", - } - } - > - <div - draggable={true} - onDragEnd={[Function]} - onDragStart={[Function]} - style={ - Object { - "alignItems": "center", - "background": "#ddd", - "display": "flex", - "height": 100, - "justifyContent": "center", - "width": 100, - } - } - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 9v1.5h16V9H4zm12 5.5h4V13h-4v1.5zm-6 0h4V13h-4v1.5zm-6 0h4V13H4v1.5z" - /> - </svg> - </div> - </div> -</div> -`; - -exports[`Storyshots Components/Dropdown Default 1`] = ` -Array [ - <div> - <p> - This is a DropdownMenu component: - </p> - <div - className="components-dropdown components-dropdown-menu" - > - <button - aria-expanded={false} - aria-haspopup="true" - aria-label="Select a direction" - className="components-button components-dropdown-menu__toggle has-icon" - onBlur={[Function]} - onClick={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onMouseDown={[Function]} - onMouseEnter={[Function]} - onMouseLeave={[Function]} - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 9v1.5h16V9H4zm12 5.5h4V13h-4v1.5zm-6 0h4V13h-4v1.5zm-6 0h4V13H4v1.5z" - /> - </svg> - </button> - </div> - </div>, - <div> - <p> - This is an assembled Dropdown component: - </p> - <div - className="components-dropdown my-container-class-name" - > - <button - aria-expanded={false} - aria-label="Select a direction" - className="components-button has-icon" - onBlur={[Function]} - onClick={[Function]} - onFocus={[Function]} - onMouseDown={[Function]} - onMouseEnter={[Function]} - onMouseLeave={[Function]} - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 9v1.5h16V9H4zm12 5.5h4V13h-4v1.5zm-6 0h4V13h-4v1.5zm-6 0h4V13H4v1.5z" - /> - </svg> - </button> - </div> - </div>, -] -`; - -exports[`Storyshots Components/Experimental/Text Body 1`] = ` -.emotion-0 { - margin: 0; - font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; - font-weight: 400; - font-size: 16px; - line-height: 24px; -} - -<p - className="emotion-0 emotion-1" -> - Body -</p> -`; - -exports[`Storyshots Components/Experimental/Text Body Small 1`] = ` -.emotion-0 { - margin: 0; - font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; - font-weight: 400; - font-size: 14px; - line-height: 20px; -} - -<p - className="emotion-0 emotion-1" -> - Body Small -</p> -`; - -exports[`Storyshots Components/Experimental/Text Button 1`] = ` -.emotion-0 { - margin: 0; - font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; - font-weight: 600; - font-size: 14px; - line-height: 20px; -} - -<p - className="emotion-0 emotion-1" -> - Button -</p> -`; - -exports[`Storyshots Components/Experimental/Text Caption 1`] = ` -.emotion-0 { - margin: 0; - font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; - font-weight: 400; - font-size: 12px; - line-height: 16px; -} - -<p - className="emotion-0 emotion-1" -> - Caption -</p> -`; - -exports[`Storyshots Components/Experimental/Text Default 1`] = ` -Array [ - .emotion-0 { - margin: 0; - font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; - font-weight: 400; - font-size: 32px; - line-height: 40px; -} - -<h1 - className="emotion-0 emotion-1" - > - Title Large - </h1>, - .emotion-0 { - margin: 0; - font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; - font-weight: 400; - font-size: 24px; - line-height: 32px; -} - -<h2 - className="emotion-0 emotion-1" - > - Title Medium - </h2>, - .emotion-0 { - margin: 0; - font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; - font-weight: 400; - font-size: 20px; - line-height: 28px; -} - -<h3 - className="emotion-0 emotion-1" - > - Title Small - </h3>, - .emotion-0 { - margin: 0; - font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; - font-weight: 600; - font-size: 14px; - line-height: 20px; - font-size: 16px; - line-height: 24px; -} - -<p - className="emotion-0 emotion-1" - > - Subtitle - </p>, - .emotion-0 { - margin: 0; - font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; - font-weight: 600; - font-size: 14px; - line-height: 20px; - font-size: 14px; - line-height: 20px; -} - -<p - className="emotion-0 emotion-1" - > - Subtitle Small - </p>, - .emotion-0 { - margin: 0; - font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; - font-weight: 400; - font-size: 16px; - line-height: 24px; -} - -<p - className="emotion-0 emotion-1" - > - Body - </p>, - .emotion-0 { - margin: 0; - font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; - font-weight: 400; - font-size: 14px; - line-height: 20px; -} - -<p - className="emotion-0 emotion-1" - > - Body Small - </p>, - .emotion-0 { - margin: 0; - font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; - font-weight: 600; - font-size: 14px; - line-height: 20px; -} - -<p - className="emotion-0 emotion-1" - > - Button - </p>, - .emotion-0 { - margin: 0; - font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; - font-weight: 400; - font-size: 12px; - line-height: 16px; -} - -<p - className="emotion-0 emotion-1" - > - Caption - </p>, - .emotion-0 { - margin: 0; - font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; - font-weight: 600; - font-size: 12px; - line-height: 16px; -} - -<p - className="emotion-0 emotion-1" - > - Label - </p>, -] -`; - -exports[`Storyshots Components/Experimental/Text Label 1`] = ` -.emotion-0 { - margin: 0; - font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; - font-weight: 600; - font-size: 12px; - line-height: 16px; -} - -<p - className="emotion-0 emotion-1" -> - Label -</p> -`; - -exports[`Storyshots Components/Experimental/Text Subtitle 1`] = ` -.emotion-0 { - margin: 0; - font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; - font-weight: 600; - font-size: 14px; - line-height: 20px; - font-size: 16px; - line-height: 24px; -} - -<p - className="emotion-0 emotion-1" -> - Subtitle -</p> -`; - -exports[`Storyshots Components/Experimental/Text Subtitle Small 1`] = ` -.emotion-0 { - margin: 0; - font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; - font-weight: 600; - font-size: 14px; - line-height: 20px; - font-size: 14px; - line-height: 20px; -} - -<p - className="emotion-0 emotion-1" -> - Subtitle Small -</p> -`; - -exports[`Storyshots Components/Experimental/Text Title Large 1`] = ` -.emotion-0 { - margin: 0; - font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; - font-weight: 400; - font-size: 32px; - line-height: 40px; -} - -<h1 - className="emotion-0 emotion-1" -> - Title Large -</h1> -`; - -exports[`Storyshots Components/Experimental/Text Title Medium 1`] = ` -.emotion-0 { - margin: 0; - font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; - font-weight: 400; - font-size: 24px; - line-height: 32px; -} - -<h2 - className="emotion-0 emotion-1" -> - Title Medium -</h2> -`; - -exports[`Storyshots Components/Experimental/Text Title Small 1`] = ` -.emotion-0 { - margin: 0; - font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; - font-weight: 400; - font-size: 20px; - line-height: 28px; -} - -<h3 - className="emotion-0 emotion-1" -> - Title Small -</h3> -`; - -exports[`Storyshots Components/ExternalLink Default 1`] = ` -<a - className="components-external-link" - href="https://wordpress.org" - rel="external noreferrer noopener" - target="_blank" -> - WordPress - <span - className="components-visually-hidden" - > - (opens in a new tab) - </span> - <svg - aria-hidden="true" - className="components-external-link__icon" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18.2 17c0 .7-.6 1.2-1.2 1.2H7c-.7 0-1.2-.6-1.2-1.2V7c0-.7.6-1.2 1.2-1.2h3.2V4.2H7C5.5 4.2 4.2 5.5 4.2 7v10c0 1.5 1.2 2.8 2.8 2.8h10c1.5 0 2.8-1.2 2.8-2.8v-3.6h-1.5V17zM14.9 3v1.5h3.7l-6.4 6.4 1.1 1.1 6.4-6.4v3.7h1.5V3h-6.3z" - /> - </svg> -</a> -`; - -exports[`Storyshots Components/FontSizePicker Default 1`] = ` -<fieldset - className="components-font-size-picker" -> - <legend - className="components-visually-hidden" - > - Font size - </legend> - <div - className="components-font-size-picker__controls" - > - <div - className="components-custom-select-control components-font-size-picker__select" - > - <label - className="components-custom-select-control__label" - htmlFor="downshift-null-toggle-button" - id="downshift-null-label" - > - Preset size - </label> - <button - aria-expanded={false} - aria-haspopup="listbox" - aria-label="Preset size" - className="components-button components-custom-select-control__button is-small" - id="downshift-null-toggle-button" - onClick={[Function]} - onKeyDown={[Function]} - type="button" - > - Normal - <svg - aria-hidden="true" - className="components-custom-select-control__button-icon" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M17 9.4L12 14 7 9.4l-1 1.2 6 5.4 6-5.4z" - /> - </svg> - </button> - <ul - aria-labelledby="downshift-null-label" - className="components-custom-select-control__menu" - id="downshift-null-menu" - onBlur={[Function]} - onKeyDown={[Function]} - onMouseLeave={[Function]} - role="listbox" - tabIndex={-1} - /> - </div> - <div - className="components-font-size-picker__number-container" - > - <label - htmlFor="components-font-size-picker__number#0" - > - Custom - </label> - <input - aria-label="Custom" - className="components-font-size-picker__number" - id="components-font-size-picker__number#0" - onChange={[Function]} - type="number" - value={16} - /> - </div> - <button - className="components-button components-color-palette__clear is-secondary is-small" - disabled={false} - onClick={[Function]} - type="button" - > - Reset - </button> - </div> -</fieldset> -`; - -exports[`Storyshots Components/FontSizePicker With Slider 1`] = ` -.emotion-20 { - -webkit-tap-highlight-color: transparent; - box-sizing: border-box; - cursor: pointer; - -webkit-align-items: flex-start; - -webkit-box-align: flex-start; - -ms-flex-align: flex-start; - align-items: flex-start; - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; - -webkit-box-pack: start; - -webkit-justify-content: flex-start; - -ms-flex-pack: start; - justify-content: flex-start; - padding: 0; - position: relative; - touch-action: none; - width: 100%; -} - -.emotion-0 { - margin-top: 3px; - margin-right: 6px; -} - -.emotion-14 { - box-sizing: border-box; - color: #007cba; - display: block; - padding-top: 15px; - position: relative; - width: 100%; - height: 30px; - min-height: 30px; - margin-left: 10px; -} - -.emotion-2 { - box-sizing: border-box; - cursor: pointer; - display: block; - height: 100%; - left: 0; - margin: 0; - opacity: 0; - outline: none; - position: absolute; - right: 0; - top: 0; - width: 100%; -} - -.emotion-4 { - background-color: #d7dade; - box-sizing: border-box; - left: 0; - pointer-events: none; - right: 0; - display: block; - height: 3px; - position: absolute; - margin-top: 14px; - top: 0; -} - -.emotion-6 { - background-color: currentColor; - border-radius: 1px; - box-sizing: border-box; - height: 3px; - pointer-events: none; - display: block; - position: absolute; - margin-top: 14px; - top: 0; -} - -.emotion-10 { - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - box-sizing: border-box; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - height: 20px; - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; - justify-content: center; - margin-top: 5px; - outline: 0; - pointer-events: none; - position: absolute; - top: 0; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - width: 20px; - margin-left: -10px; -} - -.emotion-8 { - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - background-color: white; - border-radius: 50%; - border: 1px solid #7e8993; - box-sizing: border-box; - height: 100%; - outline: 0; - pointer-events: none; - position: absolute; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - width: 100%; - border-color: #7e8993; - box-shadow: 0 0 0 rgba(0,0,0,0); -} - -.emotion-12 { - background: #23282d; - border-radius: 3px; - box-sizing: border-box; - color: white; - display: inline-block; - font-size: 11px; - min-width: 32px; - opacity: 0; - padding: 8px; - pointer-events: none; - position: absolute; - text-align: center; - -webkit-transition: opacity 120ms ease; - transition: opacity 120ms ease; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - opacity: 0; - margin-top: -4px; - top: -100%; - -webkit-transform: translateX(-50%); - -ms-transform: translateX(-50%); - transform: translateX(-50%); -} - -.emotion-12::after { - border: 6px solid #23282d; - border-left-color: transparent; - border-right-color: transparent; - bottom: -6px; - box-sizing: border-box; - content: ''; - height: 0; - left: 50%; - line-height: 0; - margin-left: -6px; - position: absolute; - width: 0; -} - -.emotion-12::after { - border-bottom: none; - border-top-style: solid; - bottom: -6px; -} - -@media ( prefers-reduced-motion:reduce ) { - .emotion-12 { - -webkit-transition-duration: 0ms; - transition-duration: 0ms; - } -} - -.emotion-16 { - margin-top: 3px; - margin-left: 16px; -} - -.emotion-18 { - box-sizing: border-box; - display: inline-block; - margin-top: 0; - min-width: 54px; - max-width: 120px; - margin-left: 16px; -} - -input[type='number'].emotion-18 { - height: 30px; - min-height: 30px; -} - -<fieldset - className="components-font-size-picker" -> - <legend - className="components-visually-hidden" - > - Font size - </legend> - <div - className="components-font-size-picker__controls" - > - <div - className="components-custom-select-control components-font-size-picker__select" - > - <label - className="components-custom-select-control__label" - htmlFor="downshift-null-toggle-button" - id="downshift-null-label" - > - Preset size - </label> - <button - aria-expanded={false} - aria-haspopup="listbox" - aria-label="Preset size" - className="components-button components-custom-select-control__button is-small" - id="downshift-null-toggle-button" - onClick={[Function]} - onKeyDown={[Function]} - type="button" - > - Normal - <svg - aria-hidden="true" - className="components-custom-select-control__button-icon" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M17 9.4L12 14 7 9.4l-1 1.2 6 5.4 6-5.4z" - /> - </svg> - </button> - <ul - aria-labelledby="downshift-null-label" - className="components-custom-select-control__menu" - id="downshift-null-menu" - onBlur={[Function]} - onKeyDown={[Function]} - onMouseLeave={[Function]} - role="listbox" - tabIndex={-1} - /> - </div> - <button - className="components-button components-color-palette__clear is-secondary is-small" - disabled={false} - onClick={[Function]} - type="button" - > - Reset - </button> - </div> - <div - className="components-base-control components-range-control components-font-size-picker__custom-input" - > - <div - className="components-base-control__field" - > - <label - className="components-base-control__label" - htmlFor="inspector-range-control-0" - > - Custom Size - </label> - <span - className="components-range-control__root emotion-20 emotion-21" - > - <span - className="emotion-0 emotion-1" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13.23 15h1.9L11 4H9L5 15h1.88l1.07-3h4.18zm-1.53-4.54H8.51L10 5.6z" - /> - </svg> - </span> - <span - className="components-range-control__wrapper emotion-14 emotion-15" - color="#00669b" - > - <input - aria-hidden={false} - aria-label="Custom Size" - className="components-range-control__slider emotion-2 emotion-3" - disabled={false} - id="inspector-range-control-0" - max={100} - min={12} - onBlur={[Function]} - onChange={[Function]} - onFocus={[Function]} - onMouseLeave={[Function]} - onMouseMove={[Function]} - step={1} - tabIndex={0} - type="range" - value={16} - /> - <span - aria-hidden={true} - className="emotion-4 emotion-5" - disabled={false} - /> - <span - aria-hidden={true} - className="components-range-control__track emotion-6 emotion-7" - disabled={false} - style={ - Object { - "width": "4.545454545454546%", - } - } - /> - <span - className="emotion-10 emotion-11" - style={ - Object { - "left": "4.545454545454546%", - } - } - > - <span - aria-hidden={true} - className="emotion-8 emotion-9" - /> - </span> - <span - aria-hidden={false} - className="components-simple-tooltip components-range-control__tooltip emotion-12 emotion-13" - role="tooltip" - style={ - Object { - "left": "4.545454545454546%", - "zIndex": 100, - } - } - > - 16 - </span> - </span> - <span - className="emotion-16 emotion-17" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13.23 15h1.9L11 4H9L5 15h1.88l1.07-3h4.18zm-1.53-4.54H8.51L10 5.6z" - /> - </svg> - </span> - <input - aria-label="Custom Size" - className="components-range-control__number emotion-18 emotion-153" - disabled={false} - inputMode="decimal" - max={100} - min={12} - onChange={[Function]} - step={1} - type="number" - value={16} - /> - </span> - </div> - </div> -</fieldset> -`; - -exports[`Storyshots Components/FontSizePicker Without Custom Sizes 1`] = ` -<fieldset - className="components-font-size-picker" -> - <legend - className="components-visually-hidden" - > - Font size - </legend> - <div - className="components-font-size-picker__controls" - > - <div - className="components-custom-select-control components-font-size-picker__select" - > - <label - className="components-custom-select-control__label" - htmlFor="downshift-null-toggle-button" - id="downshift-null-label" - > - Preset size - </label> - <button - aria-expanded={false} - aria-haspopup="listbox" - aria-label="Preset size" - className="components-button components-custom-select-control__button is-small" - id="downshift-null-toggle-button" - onClick={[Function]} - onKeyDown={[Function]} - type="button" - > - Normal - <svg - aria-hidden="true" - className="components-custom-select-control__button-icon" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M17 9.4L12 14 7 9.4l-1 1.2 6 5.4 6-5.4z" - /> - </svg> - </button> - <ul - aria-labelledby="downshift-null-label" - className="components-custom-select-control__menu" - id="downshift-null-menu" - onBlur={[Function]} - onKeyDown={[Function]} - onMouseLeave={[Function]} - role="listbox" - tabIndex={-1} - /> - </div> - <button - className="components-button components-color-palette__clear is-secondary is-small" - disabled={false} - onClick={[Function]} - type="button" - > - Reset - </button> - </div> -</fieldset> -`; - -exports[`Storyshots Components/Guide Default 1`] = ` -<button - className="components-button is-secondary" - onClick={[Function]} - type="button" -> - Open Guide -</button> -`; - -exports[`Storyshots Components/Icon Colors 1`] = ` -Array [ - <div - style={ - Object { - "color": "blue", - "display": "inline-block", - "padding": 20, - } - } - > - <svg - aria-hidden="true" - className="dashicon dashicons-screenoptions" - focusable="false" - height={20} - role="img" - viewBox="0 0 20 20" - width={20} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9 9V3H3v6h6zm8 0V3h-6v6h6zm-8 8v-6H3v6h6zm8 0v-6h-6v6h6z" - /> - </svg> - <div - style={ - Object { - "fontSize": 12, - } - } - > - 24 - px - </div> - </div>, - <div - style={ - Object { - "color": "purple", - "display": "inline-block", - "padding": 20, - } - } - > - <svg - aria-hidden="true" - className="dashicon dashicons-screenoptions" - focusable="false" - height={20} - role="img" - viewBox="0 0 20 20" - width={20} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9 9V3H3v6h6zm8 0V3h-6v6h6zm-8 8v-6H3v6h6zm8 0v-6h-6v6h6z" - /> - </svg> - <div - style={ - Object { - "fontSize": 12, - } - } - > - 24 - px - </div> - </div>, - <div - style={ - Object { - "color": "green", - "display": "inline-block", - "padding": 20, - } - } - > - <svg - aria-hidden="true" - className="dashicon dashicons-screenoptions" - focusable="false" - height={20} - role="img" - viewBox="0 0 20 20" - width={20} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9 9V3H3v6h6zm8 0V3h-6v6h6zm-8 8v-6H3v6h6zm8 0v-6h-6v6h6z" - /> - </svg> - <div - style={ - Object { - "fontSize": 12, - } - } - > - 24 - px - </div> - </div>, -] -`; - -exports[`Storyshots Components/Icon Default 1`] = ` -<div> - <svg - aria-hidden="true" - className="dashicon dashicons-screenoptions" - focusable="false" - height="24" - role="img" - viewBox="0 0 20 20" - width="24" - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9 9V3H3v6h6zm8 0V3h-6v6h6zm-8 8v-6H3v6h6zm8 0v-6h-6v6h6z" - /> - </svg> - <div - style={ - Object { - "fontSize": 12, - } - } - > - 24 - px - </div> -</div> -`; - -exports[`Storyshots Components/Icon Sizes 1`] = ` -Array [ - <div - style={ - Object { - "display": "inline-block", - "padding": 20, - } - } - > - <svg - aria-hidden="true" - className="dashicon dashicons-screenoptions" - focusable="false" - height={14} - role="img" - viewBox="0 0 20 20" - width={14} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9 9V3H3v6h6zm8 0V3h-6v6h6zm-8 8v-6H3v6h6zm8 0v-6h-6v6h6z" - /> - </svg> - <div - style={ - Object { - "fontSize": 12, - } - } - > - 14 - px - </div> - </div>, - <div - style={ - Object { - "display": "inline-block", - "padding": 20, - } - } - > - <svg - aria-hidden="true" - className="dashicon dashicons-screenoptions" - focusable="false" - height={16} - role="img" - viewBox="0 0 20 20" - width={16} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9 9V3H3v6h6zm8 0V3h-6v6h6zm-8 8v-6H3v6h6zm8 0v-6h-6v6h6z" - /> - </svg> - <div - style={ - Object { - "fontSize": 12, - } - } - > - 16 - px - </div> - </div>, - <div - style={ - Object { - "display": "inline-block", - "padding": 20, - } - } - > - <svg - aria-hidden="true" - className="dashicon dashicons-screenoptions" - focusable="false" - height={20} - role="img" - viewBox="0 0 20 20" - width={20} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9 9V3H3v6h6zm8 0V3h-6v6h6zm-8 8v-6H3v6h6zm8 0v-6h-6v6h6z" - /> - </svg> - <div - style={ - Object { - "fontSize": 12, - } - } - > - 20 - px - </div> - </div>, - <div - style={ - Object { - "display": "inline-block", - "padding": 20, - } - } - > - <svg - aria-hidden="true" - className="dashicon dashicons-screenoptions" - focusable="false" - height={24} - role="img" - viewBox="0 0 20 20" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9 9V3H3v6h6zm8 0V3h-6v6h6zm-8 8v-6H3v6h6zm8 0v-6h-6v6h6z" - /> - </svg> - <div - style={ - Object { - "fontSize": 12, - } - } - > - 24 - px - </div> - </div>, - <div - style={ - Object { - "display": "inline-block", - "padding": 20, - } - } - > - <svg - aria-hidden="true" - className="dashicon dashicons-screenoptions" - focusable="false" - height={28} - role="img" - viewBox="0 0 20 20" - width={28} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9 9V3H3v6h6zm8 0V3h-6v6h6zm-8 8v-6H3v6h6zm8 0v-6h-6v6h6z" - /> - </svg> - <div - style={ - Object { - "fontSize": 12, - } - } - > - 28 - px - </div> - </div>, - <div - style={ - Object { - "display": "inline-block", - "padding": 20, - } - } - > - <svg - aria-hidden="true" - className="dashicon dashicons-screenoptions" - focusable="false" - height={32} - role="img" - viewBox="0 0 20 20" - width={32} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9 9V3H3v6h6zm8 0V3h-6v6h6zm-8 8v-6H3v6h6zm8 0v-6h-6v6h6z" - /> - </svg> - <div - style={ - Object { - "fontSize": 12, - } - } - > - 32 - px - </div> - </div>, - <div - style={ - Object { - "display": "inline-block", - "padding": 20, - } - } - > - <svg - aria-hidden="true" - className="dashicon dashicons-screenoptions" - focusable="false" - height={40} - role="img" - viewBox="0 0 20 20" - width={40} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9 9V3H3v6h6zm8 0V3h-6v6h6zm-8 8v-6H3v6h6zm8 0v-6h-6v6h6z" - /> - </svg> - <div - style={ - Object { - "fontSize": 12, - } - } - > - 40 - px - </div> - </div>, - <div - style={ - Object { - "display": "inline-block", - "padding": 20, - } - } - > - <svg - aria-hidden="true" - className="dashicon dashicons-screenoptions" - focusable="false" - height={48} - role="img" - viewBox="0 0 20 20" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9 9V3H3v6h6zm8 0V3h-6v6h6zm-8 8v-6H3v6h6zm8 0v-6h-6v6h6z" - /> - </svg> - <div - style={ - Object { - "fontSize": 12, - } - } - > - 48 - px - </div> - </div>, - <div - style={ - Object { - "display": "inline-block", - "padding": 20, - } - } - > - <svg - aria-hidden="true" - className="dashicon dashicons-screenoptions" - focusable="false" - height={56} - role="img" - viewBox="0 0 20 20" - width={56} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9 9V3H3v6h6zm8 0V3h-6v6h6zm-8 8v-6H3v6h6zm8 0v-6h-6v6h6z" - /> - </svg> - <div - style={ - Object { - "fontSize": 12, - } - } - > - 56 - px - </div> - </div>, -] -`; - -exports[`Storyshots Components/Icon With A Component 1`] = ` -<svg - aria-hidden="true" - focusable="false" - role="img" -> - <path - d="M5 4v3h5.5v12h3V7H19V4z" - /> -</svg> -`; - -exports[`Storyshots Components/Icon With A Function 1`] = ` -<svg - aria-hidden="true" - focusable="false" - role="img" -> - <path - d="M5 4v3h5.5v12h3V7H19V4z" - /> -</svg> -`; - -exports[`Storyshots Components/Icon With An SVG 1`] = ` -<svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - width={24} -> - <path - d="M5 4v3h5.5v12h3V7H19V4z" - /> -</svg> -`; - -exports[`Storyshots Components/Modal Default 1`] = ` -<button - className="components-button is-secondary" - onClick={[Function]} - type="button" -> - Open Modal -</button> -`; - -exports[`Storyshots Components/Panel Default 1`] = ` -<div - className="components-panel" -> - <div - className="components-panel__header" - > - <h2> - My Panel - </h2> - </div> - <div - className="components-panel__body is-opened" - > - <h2 - className="components-panel__body-title" - > - <button - aria-expanded={true} - className="components-button components-panel__body-toggle" - onClick={[Function]} - type="button" - > - <span - aria-hidden="true" - > - <svg - aria-hidden="true" - className="components-panel__arrow" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M12 8l-6 5.4 1 1.2 5-4.6 5 4.6 1-1.2z" - /> - </svg> - </span> - My Block Settings - </button> - </h2> - <div - className="components-panel__row" - > - My Panel Inputs and Labels - </div> - </div> -</div> -`; - -exports[`Storyshots Components/Panel Multiple Bodies 1`] = ` -<div - className="components-panel" -> - <div - className="components-panel__header" - > - <h2> - My Panel - </h2> - </div> - <div - className="components-panel__body is-opened" - > - <h2 - className="components-panel__body-title" - > - <button - aria-expanded={true} - className="components-button components-panel__body-toggle" - onClick={[Function]} - type="button" - > - <span - aria-hidden="true" - > - <svg - aria-hidden="true" - className="components-panel__arrow" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M12 8l-6 5.4 1 1.2 5-4.6 5 4.6 1-1.2z" - /> - </svg> - </span> - First Settings - </button> - </h2> - <div - className="components-panel__row" - > - My Panel Inputs and Labels - </div> - </div> - <div - className="components-panel__body" - > - <h2 - className="components-panel__body-title" - > - <button - aria-expanded={false} - className="components-button components-panel__body-toggle" - onClick={[Function]} - type="button" - > - <span - aria-hidden="true" - > - <svg - aria-hidden="true" - className="components-panel__arrow" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M17 9.4L12 14 7 9.4l-1 1.2 6 5.4 6-5.4z" - /> - </svg> - </span> - Second Settings - </button> - </h2> - </div> -</div> -`; - -exports[`Storyshots Components/Panel With Icon 1`] = ` -<div - className="components-panel" -> - <div - className="components-panel__header" - > - <h2> - My Panel - </h2> - </div> - <div - className="components-panel__body is-opened" - > - <h2 - className="components-panel__body-title" - > - <button - aria-expanded={true} - className="components-button components-panel__body-toggle" - onClick={[Function]} - type="button" - > - <span - aria-hidden="true" - > - <svg - aria-hidden="true" - className="components-panel__arrow" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M12 8l-6 5.4 1 1.2 5-4.6 5 4.6 1-1.2z" - /> - </svg> - </span> - My Block Settings - <svg - aria-hidden="true" - className="dashicon dashicons-wordpress components-panel__icon" - focusable="false" - height={20} - role="img" - viewBox="0 0 20 20" - width={20} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M20 10c0-5.52-4.48-10-10-10S0 4.48 0 10s4.48 10 10 10 10-4.48 10-10zM10 1.01c4.97 0 8.99 4.02 8.99 8.99s-4.02 8.99-8.99 8.99S1.01 14.97 1.01 10 5.03 1.01 10 1.01zM8.01 14.82L4.96 6.61c.49-.03 1.05-.08 1.05-.08.43-.05.38-1.01-.06-.99 0 0-1.29.1-2.13.1-.15 0-.33 0-.52-.01 1.44-2.17 3.9-3.6 6.7-3.6 2.09 0 3.99.79 5.41 2.09-.6-.08-1.45.35-1.45 1.42 0 .66.38 1.22.79 1.88.31.54.5 1.22.5 2.21 0 1.34-1.27 4.48-1.27 4.48l-2.71-7.5c.48-.03.75-.16.75-.16.43-.05.38-1.1-.05-1.08 0 0-1.3.11-2.14.11-.78 0-2.11-.11-2.11-.11-.43-.02-.48 1.06-.05 1.08l.84.08 1.12 3.04zm6.02 2.15L16.64 10s.67-1.69.39-3.81c.63 1.14.94 2.42.94 3.81 0 2.96-1.56 5.58-3.94 6.97zM2.68 6.77L6.5 17.25c-2.67-1.3-4.47-4.08-4.47-7.25 0-1.16.2-2.23.65-3.23zm7.45 4.53l2.29 6.25c-.75.27-1.57.42-2.42.42-.72 0-1.41-.11-2.06-.3z" - /> - </svg> - </button> - </h2> - <div - className="components-panel__row" - > - My Panel Inputs and Labels - </div> - </div> -</div> -`; - -exports[`Storyshots Components/Placeholder Default 1`] = ` -<div - className="components-placeholder is-large" -> - <div - className="components-placeholder__label" - > - <svg - aria-hidden="true" - className="dashicon dashicons-smiley" - focusable="false" - height={20} - role="img" - viewBox="0 0 20 20" - width={20} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M7 5.2c1.1 0 2 .89 2 2 0 .37-.11.71-.28 1C8.72 8.2 8 8 7 8s-1.72.2-1.72.2c-.17-.29-.28-.63-.28-1 0-1.11.9-2 2-2zm6 0c1.11 0 2 .89 2 2 0 .37-.11.71-.28 1 0 0-.72-.2-1.72-.2s-1.72.2-1.72.2c-.17-.29-.28-.63-.28-1 0-1.11.89-2 2-2zm-3 13.7c3.72 0 7.03-2.36 8.23-5.88l-1.32-.46C15.9 15.52 13.12 17.5 10 17.5s-5.9-1.98-6.91-4.94l-1.32.46c1.2 3.52 4.51 5.88 8.23 5.88z" - /> - </svg> - My Placeholder Label - </div> - <div - className="components-placeholder__instructions" - > - Here are instructions you should follow - </div> - <div - className="components-placeholder__fieldset" - > - <div> - <div - className="components-base-control" - > - <div - className="components-base-control__field" - > - <label - className="components-base-control__label" - htmlFor="inspector-text-control-2" - > - Sample Field - </label> - <input - className="components-text-control__input" - id="inspector-text-control-2" - onChange={[Function]} - placeholder="Enter something here" - type="text" - /> - </div> - </div> - </div> - </div> -</div> -`; - -exports[`Storyshots Components/Popover Default 1`] = ` -<span> - <div - onKeyDown={[Function]} - tabIndex="-1" - > - <div - onBlur={[Function]} - onFocus={[Function]} - > - <div - onBlur={[Function]} - onFocus={[Function]} - onMouseDown={[Function]} - onMouseUp={[Function]} - onTouchEnd={[Function]} - onTouchStart={[Function]} - > - <div - className="components-popover" - onKeyDown={[Function]} - onMouseDown={[Function]} - > - <div - className="components-popover__content" - tabIndex="-1" - > - Popover Content - </div> - </div> - </div> - </div> - </div> -</span> -`; - -exports[`Storyshots Components/Popover Positioning 1`] = ` -<div> - <div - style={ - Object { - "color": "#555", - "position": "absolute", - } - } - > - <p> - Move the gray box around. - </p> - <p> - The - - <strong - style={ - Object { - "background": "pink", - } - } - > - pink bordered - </strong> - - element is a parent. - </p> - <p> - The - - <strong - style={ - Object { - "background": "cyan", - } - } - > - cyan bordered - </strong> - - element is a sibling to - <strong> - Popover - </strong> - . - </p> - <p> - <strong> - Popover - </strong> - aligns to the content within parent. - </p> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - "height": "100vh", - "justifyContent": "center", - "width": "100%", - } - } - > - <div - onMouseDown={[Function]} - onMouseUp={[Function]} - style={ - Object { - "background": "#ddd", - "border": "2px solid pink", - "borderRadius": 4, - "left": 0, - "padding": 10, - "position": "relative", - "top": 0, - "userSelect": "none", - } - } - > - <div - style={ - Object { - "border": "2px solid cyan", - } - } - > - Drag Me! - </div> - <span> - <div - onKeyDown={[Function]} - tabIndex="-1" - > - <div - onBlur={[Function]} - onFocus={[Function]} - > - <div - onBlur={[Function]} - onFocus={[Function]} - onMouseDown={[Function]} - onMouseUp={[Function]} - onTouchEnd={[Function]} - onTouchStart={[Function]} - > - <div - className="components-popover" - onKeyDown={[Function]} - onMouseDown={[Function]} - > - <div - className="components-popover__content" - tabIndex="-1" - > - Popover - </div> - </div> - </div> - </div> - </div> - </span> - </div> - </div> -</div> -`; - -exports[`Storyshots Components/RadioControl Default 1`] = ` -<div - className="components-base-control components-radio-control" -> - <div - className="components-base-control__field" - > - <label - className="components-base-control__label" - htmlFor="inspector-radio-control-0" - > - Post visibility - </label> - <div - className="components-radio-control__option" - > - <input - checked={true} - className="components-radio-control__input" - id="inspector-radio-control-0-0" - name="inspector-radio-control-0" - onChange={[Function]} - type="radio" - value="public" - /> - <label - htmlFor="inspector-radio-control-0-0" - > - Public - </label> - </div> - <div - className="components-radio-control__option" - > - <input - checked={false} - className="components-radio-control__input" - id="inspector-radio-control-0-1" - name="inspector-radio-control-0" - onChange={[Function]} - type="radio" - value="private" - /> - <label - htmlFor="inspector-radio-control-0-1" - > - Private - </label> - </div> - <div - className="components-radio-control__option" - > - <input - checked={false} - className="components-radio-control__input" - id="inspector-radio-control-0-2" - name="inspector-radio-control-0" - onChange={[Function]} - type="radio" - value="password" - /> - <label - htmlFor="inspector-radio-control-0-2" - > - Password Protected - </label> - </div> - </div> -</div> -`; - -exports[`Storyshots Components/RadioControl With Help 1`] = ` -<div - className="components-base-control components-radio-control" -> - <div - className="components-base-control__field" - > - <label - className="components-base-control__label" - htmlFor="inspector-radio-control-1" - > - Post visibility - </label> - <div - className="components-radio-control__option" - > - <input - aria-describedby="inspector-radio-control-1__help" - checked={true} - className="components-radio-control__input" - id="inspector-radio-control-1-0" - name="inspector-radio-control-1" - onChange={[Function]} - type="radio" - value="public" - /> - <label - htmlFor="inspector-radio-control-1-0" - > - Public - </label> - </div> - <div - className="components-radio-control__option" - > - <input - aria-describedby="inspector-radio-control-1__help" - checked={false} - className="components-radio-control__input" - id="inspector-radio-control-1-1" - name="inspector-radio-control-1" - onChange={[Function]} - type="radio" - value="private" - /> - <label - htmlFor="inspector-radio-control-1-1" - > - Private - </label> - </div> - <div - className="components-radio-control__option" - > - <input - aria-describedby="inspector-radio-control-1__help" - checked={false} - className="components-radio-control__input" - id="inspector-radio-control-1-2" - name="inspector-radio-control-1" - onChange={[Function]} - type="radio" - value="password" - /> - <label - htmlFor="inspector-radio-control-1-2" - > - Password Protected - </label> - </div> - </div> - <p - className="components-base-control__help" - id="inspector-radio-control-1__help" - > - The visibility level for the current post - </p> -</div> -`; - -exports[`Storyshots Components/RangeControl Custom Marks 1`] = ` -.emotion-36 { - -webkit-tap-highlight-color: transparent; - box-sizing: border-box; - cursor: pointer; - -webkit-align-items: flex-start; - -webkit-box-align: flex-start; - -ms-flex-align: flex-start; - align-items: flex-start; - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; - -webkit-box-pack: start; - -webkit-justify-content: flex-start; - -ms-flex-pack: start; - justify-content: flex-start; - padding: 0; - position: relative; - touch-action: none; - width: 100%; -} - -.emotion-0 { - box-sizing: border-box; - cursor: pointer; - display: block; - height: 100%; - left: 0; - margin: 0; - opacity: 0; - outline: none; - position: absolute; - right: 0; - top: 0; - width: 100%; -} - -.emotion-2 { - background-color: #d7dade; - box-sizing: border-box; - left: 0; - pointer-events: none; - right: 0; - display: block; - height: 3px; - position: absolute; - margin-top: 14px; - top: 0; -} - -.emotion-26 { - background-color: currentColor; - border-radius: 1px; - box-sizing: border-box; - height: 3px; - pointer-events: none; - display: block; - position: absolute; - margin-top: 14px; - top: 0; -} - -.emotion-30 { - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - box-sizing: border-box; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - height: 20px; - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; - justify-content: center; - margin-top: 5px; - outline: 0; - pointer-events: none; - position: absolute; - top: 0; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - width: 20px; - margin-left: -10px; -} - -.emotion-28 { - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - background-color: white; - border-radius: 50%; - border: 1px solid #7e8993; - box-sizing: border-box; - height: 100%; - outline: 0; - pointer-events: none; - position: absolute; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - width: 100%; - border-color: #7e8993; - box-shadow: 0 0 0 rgba(0,0,0,0); -} - -.emotion-34 { - box-sizing: border-box; - display: inline-block; - margin-top: 0; - min-width: 54px; - max-width: 120px; - margin-left: 16px; -} - -input[type='number'].emotion-34 { - height: 30px; - min-height: 30px; -} - -.emotion-38 { - padding: 60px 40px; -} - -.emotion-32 { - box-sizing: border-box; - color: #007cba; - display: block; - padding-top: 15px; - position: relative; - width: 100%; - height: 30px; - min-height: 30px; - margin-bottom: 16px; - margin-left: 10px; -} - -.emotion-24 { - box-sizing: border-box; - display: block; - position: relative; - width: 100%; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} - -.emotion-4 { - box-sizing: border-box; - height: 9px; - left: 0; - position: absolute; - top: -4px; - width: 1px; - background-color: currentColor; -} - -.emotion-6 { - box-sizing: border-box; - color: #d7dade; - left: 0; - font-size: 11px; - position: absolute; - top: 12px; - -webkit-transform: translateX( -50% ); - -ms-transform: translateX( -50% ); - transform: translateX( -50% ); - white-space: nowrap; - color: #6c7781; -} - -.emotion-16 { - box-sizing: border-box; - height: 9px; - left: 0; - position: absolute; - top: -4px; - width: 1px; - background-color: #d7dade; -} - -.emotion-18 { - box-sizing: border-box; - color: #d7dade; - left: 0; - font-size: 11px; - position: absolute; - top: 12px; - -webkit-transform: translateX( -50% ); - -ms-transform: translateX( -50% ); - transform: translateX( -50% ); - white-space: nowrap; - color: #d7dade; -} - -<div - className="emotion-38 emotion-39" -> - <div - className="components-base-control components-range-control" - > - <div - className="components-base-control__field" - > - <span - className="components-range-control__root emotion-36 emotion-37" - > - <span - className="components-range-control__wrapper is-marked emotion-32 emotion-33" - color="#00669b" - > - <input - aria-hidden={false} - className="components-range-control__slider emotion-0 emotion-1" - disabled={false} - id="inspector-range-control-8" - max={10} - min={0} - onBlur={[Function]} - onChange={[Function]} - onFocus={[Function]} - onMouseLeave={[Function]} - onMouseMove={[Function]} - step={1} - tabIndex={0} - type="range" - value="" - /> - <span - aria-hidden={true} - className="emotion-2 emotion-3" - disabled={false} - /> - <span - aria-hidden="true" - className="components-range-control__marks emotion-24 emotion-25" - > - <span - aria-hidden="true" - className="components-range-control__mark is-filled emotion-4 emotion-5" - disabled={false} - style={ - Object { - "left": "0%", - } - } - value={0} - /> - <span - aria-hidden="true" - className="components-range-control__mark-label is-filled emotion-6 emotion-7" - style={ - Object { - "left": "0%", - } - } - > - 0 - </span> - <span - aria-hidden="true" - className="components-range-control__mark is-filled emotion-4 emotion-5" - disabled={false} - style={ - Object { - "left": "10%", - } - } - value={1} - /> - <span - aria-hidden="true" - className="components-range-control__mark-label is-filled emotion-6 emotion-7" - style={ - Object { - "left": "10%", - } - } - > - 1 - </span> - <span - aria-hidden="true" - className="components-range-control__mark is-filled emotion-4 emotion-5" - disabled={false} - style={ - Object { - "left": "20%", - } - } - value={2} - /> - <span - aria-hidden="true" - className="components-range-control__mark-label is-filled emotion-6 emotion-7" - style={ - Object { - "left": "20%", - } - } - > - 2 - </span> - <span - aria-hidden="true" - className="components-range-control__mark emotion-16 emotion-5" - disabled={false} - style={ - Object { - "left": "80%", - } - } - value={8} - /> - <span - aria-hidden="true" - className="components-range-control__mark-label emotion-18 emotion-7" - style={ - Object { - "left": "80%", - } - } - > - 8 - </span> - <span - aria-hidden="true" - className="components-range-control__mark emotion-16 emotion-5" - disabled={false} - style={ - Object { - "left": "100%", - } - } - value={10} - /> - <span - aria-hidden="true" - className="components-range-control__mark-label emotion-18 emotion-7" - style={ - Object { - "left": "100%", - } - } - > - 10 - </span> - </span> - <span - aria-hidden={true} - className="components-range-control__track emotion-26 emotion-27" - disabled={false} - style={ - Object { - "width": "50%", - } - } - /> - <span - className="emotion-30 emotion-31" - style={ - Object { - "left": "50%", - } - } - > - <span - aria-hidden={true} - className="emotion-28 emotion-29" - /> - </span> - </span> - <input - className="components-range-control__number emotion-34 emotion-333" - disabled={false} - inputMode="decimal" - max={10} - min={0} - onChange={[Function]} - step={1} - type="number" - value="" - /> - </span> - </div> - </div> -</div> -`; - -exports[`Storyshots Components/RangeControl Default 1`] = ` -.emotion-14 { - -webkit-tap-highlight-color: transparent; - box-sizing: border-box; - cursor: pointer; - -webkit-align-items: flex-start; - -webkit-box-align: flex-start; - -ms-flex-align: flex-start; - align-items: flex-start; - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; - -webkit-box-pack: start; - -webkit-justify-content: flex-start; - -ms-flex-pack: start; - justify-content: flex-start; - padding: 0; - position: relative; - touch-action: none; - width: 100%; -} - -.emotion-10 { - box-sizing: border-box; - color: #007cba; - display: block; - padding-top: 15px; - position: relative; - width: 100%; - height: 30px; - min-height: 30px; - margin-left: 10px; -} - -.emotion-0 { - box-sizing: border-box; - cursor: pointer; - display: block; - height: 100%; - left: 0; - margin: 0; - opacity: 0; - outline: none; - position: absolute; - right: 0; - top: 0; - width: 100%; -} - -.emotion-2 { - background-color: #d7dade; - box-sizing: border-box; - left: 0; - pointer-events: none; - right: 0; - display: block; - height: 3px; - position: absolute; - margin-top: 14px; - top: 0; -} - -.emotion-4 { - background-color: currentColor; - border-radius: 1px; - box-sizing: border-box; - height: 3px; - pointer-events: none; - display: block; - position: absolute; - margin-top: 14px; - top: 0; -} - -.emotion-8 { - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - box-sizing: border-box; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - height: 20px; - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; - justify-content: center; - margin-top: 5px; - outline: 0; - pointer-events: none; - position: absolute; - top: 0; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - width: 20px; - margin-left: -10px; -} - -.emotion-6 { - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - background-color: white; - border-radius: 50%; - border: 1px solid #7e8993; - box-sizing: border-box; - height: 100%; - outline: 0; - pointer-events: none; - position: absolute; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - width: 100%; - border-color: #7e8993; - box-shadow: 0 0 0 rgba(0,0,0,0); -} - -.emotion-12 { - box-sizing: border-box; - display: inline-block; - margin-top: 0; - min-width: 54px; - max-width: 120px; - margin-left: 16px; -} - -input[type='number'].emotion-12 { - height: 30px; - min-height: 30px; -} - -.emotion-16 { - padding: 60px 40px; -} - -<div - className="emotion-16 emotion-17" -> - <div - className="components-base-control components-range-control" - > - <div - className="components-base-control__field" - > - <label - className="components-base-control__label" - htmlFor="inspector-range-control-1" - > - Range Label - </label> - <span - className="components-range-control__root emotion-14 emotion-15" - > - - <span - className="components-range-control__wrapper emotion-10 emotion-11" - color="#00669b" - > - <input - aria-hidden={false} - aria-label="Range Label" - className="components-range-control__slider emotion-0 emotion-1" - disabled={false} - id="inspector-range-control-1" - max={10} - min={0} - onBlur={[Function]} - onChange={[Function]} - onFocus={[Function]} - onMouseLeave={[Function]} - onMouseMove={[Function]} - step={1} - tabIndex={0} - type="range" - value="" - /> - <span - aria-hidden={true} - className="emotion-2 emotion-3" - disabled={false} - /> - <span - aria-hidden={true} - className="components-range-control__track emotion-4 emotion-5" - disabled={false} - style={ - Object { - "width": "50%", - } - } - /> - <span - className="emotion-8 emotion-9" - style={ - Object { - "left": "50%", - } - } - > - <span - aria-hidden={true} - className="emotion-6 emotion-7" - /> - </span> - </span> - - <input - aria-label="Range Label" - className="components-range-control__number emotion-12 emotion-113" - disabled={false} - inputMode="decimal" - max={10} - min={0} - onChange={[Function]} - step={1} - type="number" - value="" - /> - </span> - </div> - </div> -</div> -`; - -exports[`Storyshots Components/RangeControl Initial Value Zero 1`] = ` -.emotion-16 { - -webkit-tap-highlight-color: transparent; - box-sizing: border-box; - cursor: pointer; - -webkit-align-items: flex-start; - -webkit-box-align: flex-start; - -ms-flex-align: flex-start; - align-items: flex-start; - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; - -webkit-box-pack: start; - -webkit-justify-content: flex-start; - -ms-flex-pack: start; - justify-content: flex-start; - padding: 0; - position: relative; - touch-action: none; - width: 100%; -} - -.emotion-12 { - box-sizing: border-box; - color: #007cba; - display: block; - padding-top: 15px; - position: relative; - width: 100%; - height: 30px; - min-height: 30px; - margin-left: 10px; -} - -.emotion-0 { - box-sizing: border-box; - cursor: pointer; - display: block; - height: 100%; - left: 0; - margin: 0; - opacity: 0; - outline: none; - position: absolute; - right: 0; - top: 0; - width: 100%; -} - -.emotion-2 { - background-color: #d7dade; - box-sizing: border-box; - left: 0; - pointer-events: none; - right: 0; - display: block; - height: 3px; - position: absolute; - margin-top: 14px; - top: 0; -} - -.emotion-4 { - background-color: currentColor; - border-radius: 1px; - box-sizing: border-box; - height: 3px; - pointer-events: none; - display: block; - position: absolute; - margin-top: 14px; - top: 0; -} - -.emotion-8 { - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - box-sizing: border-box; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - height: 20px; - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; - justify-content: center; - margin-top: 5px; - outline: 0; - pointer-events: none; - position: absolute; - top: 0; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - width: 20px; - margin-left: -10px; -} - -.emotion-6 { - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - background-color: white; - border-radius: 50%; - border: 1px solid #7e8993; - box-sizing: border-box; - height: 100%; - outline: 0; - pointer-events: none; - position: absolute; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - width: 100%; - border-color: #7e8993; - box-shadow: 0 0 0 rgba(0,0,0,0); -} - -.emotion-10 { - background: #23282d; - border-radius: 3px; - box-sizing: border-box; - color: white; - display: inline-block; - font-size: 11px; - min-width: 32px; - opacity: 0; - padding: 8px; - pointer-events: none; - position: absolute; - text-align: center; - -webkit-transition: opacity 120ms ease; - transition: opacity 120ms ease; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - opacity: 0; - margin-top: -4px; - top: -100%; - -webkit-transform: translateX(-50%); - -ms-transform: translateX(-50%); - transform: translateX(-50%); -} - -.emotion-10::after { - border: 6px solid #23282d; - border-left-color: transparent; - border-right-color: transparent; - bottom: -6px; - box-sizing: border-box; - content: ''; - height: 0; - left: 50%; - line-height: 0; - margin-left: -6px; - position: absolute; - width: 0; -} - -.emotion-10::after { - border-bottom: none; - border-top-style: solid; - bottom: -6px; -} - -@media ( prefers-reduced-motion:reduce ) { - .emotion-10 { - -webkit-transition-duration: 0ms; - transition-duration: 0ms; - } -} - -.emotion-14 { - box-sizing: border-box; - display: inline-block; - margin-top: 0; - min-width: 54px; - max-width: 120px; - margin-left: 16px; -} - -input[type='number'].emotion-14 { - height: 30px; - min-height: 30px; -} - -<div - className="components-base-control components-range-control" -> - <div - className="components-base-control__field" - > - <label - className="components-base-control__label" - htmlFor="inspector-range-control-2" - > - How many columns should this use? - </label> - <span - className="components-range-control__root emotion-16 emotion-17" - > - <span - className="components-range-control__wrapper emotion-12 emotion-13" - color="#00669b" - > - <input - aria-hidden={false} - aria-label="How many columns should this use?" - className="components-range-control__slider emotion-0 emotion-1" - disabled={false} - id="inspector-range-control-2" - max={20} - min={0} - onBlur={[Function]} - onChange={[Function]} - onFocus={[Function]} - onMouseLeave={[Function]} - onMouseMove={[Function]} - step={1} - tabIndex={0} - type="range" - value={0} - /> - <span - aria-hidden={true} - className="emotion-2 emotion-3" - disabled={false} - /> - <span - aria-hidden={true} - className="components-range-control__track emotion-4 emotion-5" - disabled={false} - style={ - Object { - "width": "0%", - } - } - /> - <span - className="emotion-8 emotion-9" - style={ - Object { - "left": "0%", - } - } - > - <span - aria-hidden={true} - className="emotion-6 emotion-7" - /> - </span> - <span - aria-hidden={false} - className="components-simple-tooltip components-range-control__tooltip emotion-10 emotion-11" - role="tooltip" - style={ - Object { - "left": "0%", - "zIndex": 100, - } - } - > - 0 - </span> - </span> - <input - aria-label="How many columns should this use?" - className="components-range-control__number emotion-14 emotion-133" - disabled={false} - inputMode="decimal" - max={20} - min={0} - onChange={[Function]} - step={1} - type="number" - /> - </span> - </div> -</div> -`; - -exports[`Storyshots Components/RangeControl Multiple 1`] = ` -.emotion-16 { - -webkit-tap-highlight-color: transparent; - box-sizing: border-box; - cursor: pointer; - -webkit-align-items: flex-start; - -webkit-box-align: flex-start; - -ms-flex-align: flex-start; - align-items: flex-start; - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; - -webkit-box-pack: start; - -webkit-justify-content: flex-start; - -ms-flex-pack: start; - justify-content: flex-start; - padding: 0; - position: relative; - touch-action: none; - width: 100%; -} - -.emotion-12 { - box-sizing: border-box; - color: #007cba; - display: block; - padding-top: 15px; - position: relative; - width: 100%; - height: 30px; - min-height: 30px; - margin-left: 10px; -} - -.emotion-0 { - box-sizing: border-box; - cursor: pointer; - display: block; - height: 100%; - left: 0; - margin: 0; - opacity: 0; - outline: none; - position: absolute; - right: 0; - top: 0; - width: 100%; -} - -.emotion-2 { - background-color: #d7dade; - box-sizing: border-box; - left: 0; - pointer-events: none; - right: 0; - display: block; - height: 3px; - position: absolute; - margin-top: 14px; - top: 0; -} - -.emotion-4 { - background-color: currentColor; - border-radius: 1px; - box-sizing: border-box; - height: 3px; - pointer-events: none; - display: block; - position: absolute; - margin-top: 14px; - top: 0; -} - -.emotion-8 { - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - box-sizing: border-box; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - height: 20px; - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; - justify-content: center; - margin-top: 5px; - outline: 0; - pointer-events: none; - position: absolute; - top: 0; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - width: 20px; - margin-left: -10px; -} - -.emotion-6 { - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - background-color: white; - border-radius: 50%; - border: 1px solid #7e8993; - box-sizing: border-box; - height: 100%; - outline: 0; - pointer-events: none; - position: absolute; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - width: 100%; - border-color: #7e8993; - box-shadow: 0 0 0 rgba(0,0,0,0); -} - -.emotion-10 { - background: #23282d; - border-radius: 3px; - box-sizing: border-box; - color: white; - display: inline-block; - font-size: 11px; - min-width: 32px; - opacity: 0; - padding: 8px; - pointer-events: none; - position: absolute; - text-align: center; - -webkit-transition: opacity 120ms ease; - transition: opacity 120ms ease; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - opacity: 0; - margin-top: -4px; - top: -100%; - -webkit-transform: translateX(-50%); - -ms-transform: translateX(-50%); - transform: translateX(-50%); -} - -.emotion-10::after { - border: 6px solid #23282d; - border-left-color: transparent; - border-right-color: transparent; - bottom: -6px; - box-sizing: border-box; - content: ''; - height: 0; - left: 50%; - line-height: 0; - margin-left: -6px; - position: absolute; - width: 0; -} - -.emotion-10::after { - border-bottom: none; - border-top-style: solid; - bottom: -6px; -} - -@media ( prefers-reduced-motion:reduce ) { - .emotion-10 { - -webkit-transition-duration: 0ms; - transition-duration: 0ms; - } -} - -.emotion-14 { - box-sizing: border-box; - display: inline-block; - margin-top: 0; - min-width: 54px; - max-width: 120px; - margin-left: 16px; -} - -input[type='number'].emotion-14 { - height: 30px; - min-height: 30px; -} - -.emotion-72 { - padding: 60px 40px; -} - -<div - className="emotion-72 emotion-73" -> - <div - className="components-base-control components-range-control" - > - <div - className="components-base-control__field" - > - <span - className="components-range-control__root emotion-16 emotion-17" - > - <span - className="components-range-control__wrapper emotion-12 emotion-13" - color="#00669b" - > - <input - aria-hidden={false} - className="components-range-control__slider emotion-0 emotion-1" - disabled={false} - id="inspector-range-control-9" - max={100} - min={0} - onBlur={[Function]} - onChange={[Function]} - onFocus={[Function]} - onMouseLeave={[Function]} - onMouseMove={[Function]} - step={1} - tabIndex={0} - type="range" - value={5} - /> - <span - aria-hidden={true} - className="emotion-2 emotion-3" - disabled={false} - /> - <span - aria-hidden={true} - className="components-range-control__track emotion-4 emotion-5" - disabled={false} - style={ - Object { - "width": "5%", - } - } - /> - <span - className="emotion-8 emotion-9" - style={ - Object { - "left": "5%", - } - } - > - <span - aria-hidden={true} - className="emotion-6 emotion-7" - /> - </span> - <span - aria-hidden={false} - className="components-simple-tooltip components-range-control__tooltip emotion-10 emotion-11" - role="tooltip" - style={ - Object { - "left": "5%", - "zIndex": 100, - } - } - > - 5 - </span> - </span> - <input - className="components-range-control__number emotion-14 emotion-133" - disabled={false} - inputMode="decimal" - max={100} - min={0} - onChange={[Function]} - step={1} - type="number" - value={5} - /> - </span> - </div> - </div> - <div - className="components-base-control components-range-control" - > - <div - className="components-base-control__field" - > - <span - className="components-range-control__root emotion-16 emotion-17" - > - <span - className="components-range-control__wrapper emotion-12 emotion-13" - color="#00669b" - > - <input - aria-hidden={false} - className="components-range-control__slider emotion-0 emotion-1" - disabled={false} - id="inspector-range-control-10" - max={100} - min={0} - onBlur={[Function]} - onChange={[Function]} - onFocus={[Function]} - onMouseLeave={[Function]} - onMouseMove={[Function]} - step={1} - tabIndex={0} - type="range" - value={5} - /> - <span - aria-hidden={true} - className="emotion-2 emotion-3" - disabled={false} - /> - <span - aria-hidden={true} - className="components-range-control__track emotion-4 emotion-5" - disabled={false} - style={ - Object { - "width": "5%", - } - } - /> - <span - className="emotion-8 emotion-9" - style={ - Object { - "left": "5%", - } - } - > - <span - aria-hidden={true} - className="emotion-6 emotion-7" - /> - </span> - <span - aria-hidden={false} - className="components-simple-tooltip components-range-control__tooltip emotion-10 emotion-11" - role="tooltip" - style={ - Object { - "left": "5%", - "zIndex": 100, - } - } - > - 5 - </span> - </span> - <input - className="components-range-control__number emotion-14 emotion-133" - disabled={false} - inputMode="decimal" - max={100} - min={0} - onChange={[Function]} - step={1} - type="number" - value={5} - /> - </span> - </div> - </div> - <div - className="components-base-control components-range-control" - > - <div - className="components-base-control__field" - > - <span - className="components-range-control__root emotion-16 emotion-17" - > - <span - className="components-range-control__wrapper emotion-12 emotion-13" - color="#00669b" - > - <input - aria-hidden={false} - className="components-range-control__slider emotion-0 emotion-1" - disabled={false} - id="inspector-range-control-11" - max={100} - min={0} - onBlur={[Function]} - onChange={[Function]} - onFocus={[Function]} - onMouseLeave={[Function]} - onMouseMove={[Function]} - step={1} - tabIndex={0} - type="range" - value={5} - /> - <span - aria-hidden={true} - className="emotion-2 emotion-3" - disabled={false} - /> - <span - aria-hidden={true} - className="components-range-control__track emotion-4 emotion-5" - disabled={false} - style={ - Object { - "width": "5%", - } - } - /> - <span - className="emotion-8 emotion-9" - style={ - Object { - "left": "5%", - } - } - > - <span - aria-hidden={true} - className="emotion-6 emotion-7" - /> - </span> - <span - aria-hidden={false} - className="components-simple-tooltip components-range-control__tooltip emotion-10 emotion-11" - role="tooltip" - style={ - Object { - "left": "5%", - "zIndex": 100, - } - } - > - 5 - </span> - </span> - <input - className="components-range-control__number emotion-14 emotion-133" - disabled={false} - inputMode="decimal" - max={100} - min={0} - onChange={[Function]} - step={1} - type="number" - value={5} - /> - </span> - </div> - </div> - <div - className="components-base-control components-range-control" - > - <div - className="components-base-control__field" - > - <span - className="components-range-control__root emotion-16 emotion-17" - > - <span - className="components-range-control__wrapper emotion-12 emotion-13" - color="#00669b" - > - <input - aria-hidden={false} - className="components-range-control__slider emotion-0 emotion-1" - disabled={false} - id="inspector-range-control-12" - max={100} - min={0} - onBlur={[Function]} - onChange={[Function]} - onFocus={[Function]} - onMouseLeave={[Function]} - onMouseMove={[Function]} - step={1} - tabIndex={0} - type="range" - value={5} - /> - <span - aria-hidden={true} - className="emotion-2 emotion-3" - disabled={false} - /> - <span - aria-hidden={true} - className="components-range-control__track emotion-4 emotion-5" - disabled={false} - style={ - Object { - "width": "5%", - } - } - /> - <span - className="emotion-8 emotion-9" - style={ - Object { - "left": "5%", - } - } - > - <span - aria-hidden={true} - className="emotion-6 emotion-7" - /> - </span> - <span - aria-hidden={false} - className="components-simple-tooltip components-range-control__tooltip emotion-10 emotion-11" - role="tooltip" - style={ - Object { - "left": "5%", - "zIndex": 100, - } - } - > - 5 - </span> - </span> - <input - className="components-range-control__number emotion-14 emotion-133" - disabled={false} - inputMode="decimal" - max={100} - min={0} - onChange={[Function]} - step={1} - type="number" - value={5} - /> - </span> - </div> - </div> -</div> -`; - -exports[`Storyshots Components/RangeControl With Help 1`] = ` -.emotion-16 { - -webkit-tap-highlight-color: transparent; - box-sizing: border-box; - cursor: pointer; - -webkit-align-items: flex-start; - -webkit-box-align: flex-start; - -ms-flex-align: flex-start; - align-items: flex-start; - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; - -webkit-box-pack: start; - -webkit-justify-content: flex-start; - -ms-flex-pack: start; - justify-content: flex-start; - padding: 0; - position: relative; - touch-action: none; - width: 100%; -} - -.emotion-12 { - box-sizing: border-box; - color: #007cba; - display: block; - padding-top: 15px; - position: relative; - width: 100%; - height: 30px; - min-height: 30px; - margin-left: 10px; -} - -.emotion-0 { - box-sizing: border-box; - cursor: pointer; - display: block; - height: 100%; - left: 0; - margin: 0; - opacity: 0; - outline: none; - position: absolute; - right: 0; - top: 0; - width: 100%; -} - -.emotion-2 { - background-color: #d7dade; - box-sizing: border-box; - left: 0; - pointer-events: none; - right: 0; - display: block; - height: 3px; - position: absolute; - margin-top: 14px; - top: 0; -} - -.emotion-4 { - background-color: currentColor; - border-radius: 1px; - box-sizing: border-box; - height: 3px; - pointer-events: none; - display: block; - position: absolute; - margin-top: 14px; - top: 0; -} - -.emotion-8 { - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - box-sizing: border-box; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - height: 20px; - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; - justify-content: center; - margin-top: 5px; - outline: 0; - pointer-events: none; - position: absolute; - top: 0; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - width: 20px; - margin-left: -10px; -} - -.emotion-6 { - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - background-color: white; - border-radius: 50%; - border: 1px solid #7e8993; - box-sizing: border-box; - height: 100%; - outline: 0; - pointer-events: none; - position: absolute; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - width: 100%; - border-color: #7e8993; - box-shadow: 0 0 0 rgba(0,0,0,0); -} - -.emotion-10 { - background: #23282d; - border-radius: 3px; - box-sizing: border-box; - color: white; - display: inline-block; - font-size: 11px; - min-width: 32px; - opacity: 0; - padding: 8px; - pointer-events: none; - position: absolute; - text-align: center; - -webkit-transition: opacity 120ms ease; - transition: opacity 120ms ease; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - opacity: 0; - margin-top: -4px; - top: -100%; - -webkit-transform: translateX(-50%); - -ms-transform: translateX(-50%); - transform: translateX(-50%); -} - -.emotion-10::after { - border: 6px solid #23282d; - border-left-color: transparent; - border-right-color: transparent; - bottom: -6px; - box-sizing: border-box; - content: ''; - height: 0; - left: 50%; - line-height: 0; - margin-left: -6px; - position: absolute; - width: 0; -} - -.emotion-10::after { - border-bottom: none; - border-top-style: solid; - bottom: -6px; -} - -@media ( prefers-reduced-motion:reduce ) { - .emotion-10 { - -webkit-transition-duration: 0ms; - transition-duration: 0ms; - } -} - -.emotion-14 { - box-sizing: border-box; - display: inline-block; - margin-top: 0; - min-width: 54px; - max-width: 120px; - margin-left: 16px; -} - -input[type='number'].emotion-14 { - height: 30px; - min-height: 30px; -} - -<div - className="components-base-control components-range-control" -> - <div - className="components-base-control__field" - > - <label - className="components-base-control__label" - htmlFor="inspector-range-control-3" - > - How many columns should this use? - </label> - <span - className="components-range-control__root emotion-16 emotion-17" - > - <span - className="components-range-control__wrapper emotion-12 emotion-13" - color="#00669b" - > - <input - aria-describedby="inspector-range-control-3__help" - aria-hidden={false} - aria-label="How many columns should this use?" - className="components-range-control__slider emotion-0 emotion-1" - disabled={false} - id="inspector-range-control-3" - max={100} - min={0} - onBlur={[Function]} - onChange={[Function]} - onFocus={[Function]} - onMouseLeave={[Function]} - onMouseMove={[Function]} - step={1} - tabIndex={0} - type="range" - value={5} - /> - <span - aria-hidden={true} - className="emotion-2 emotion-3" - disabled={false} - /> - <span - aria-hidden={true} - className="components-range-control__track emotion-4 emotion-5" - disabled={false} - style={ - Object { - "width": "5%", - } - } - /> - <span - className="emotion-8 emotion-9" - style={ - Object { - "left": "5%", - } - } - > - <span - aria-hidden={true} - className="emotion-6 emotion-7" - /> - </span> - <span - aria-hidden={false} - className="components-simple-tooltip components-range-control__tooltip emotion-10 emotion-11" - role="tooltip" - style={ - Object { - "left": "5%", - "zIndex": 100, - } - } - > - 5 - </span> - </span> - <input - aria-label="How many columns should this use?" - className="components-range-control__number emotion-14 emotion-133" - disabled={false} - inputMode="decimal" - max={100} - min={0} - onChange={[Function]} - step={1} - type="number" - value={5} - /> - </span> - </div> - <p - className="components-base-control__help" - id="inspector-range-control-3__help" - > - Please select the number of columns you would like this to contain. - </p> -</div> -`; - -exports[`Storyshots Components/RangeControl With Icon After 1`] = ` -.emotion-18 { - -webkit-tap-highlight-color: transparent; - box-sizing: border-box; - cursor: pointer; - -webkit-align-items: flex-start; - -webkit-box-align: flex-start; - -ms-flex-align: flex-start; - align-items: flex-start; - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; - -webkit-box-pack: start; - -webkit-justify-content: flex-start; - -ms-flex-pack: start; - justify-content: flex-start; - padding: 0; - position: relative; - touch-action: none; - width: 100%; -} - -.emotion-12 { - box-sizing: border-box; - color: #007cba; - display: block; - padding-top: 15px; - position: relative; - width: 100%; - height: 30px; - min-height: 30px; - margin-left: 10px; -} - -.emotion-0 { - box-sizing: border-box; - cursor: pointer; - display: block; - height: 100%; - left: 0; - margin: 0; - opacity: 0; - outline: none; - position: absolute; - right: 0; - top: 0; - width: 100%; -} - -.emotion-2 { - background-color: #d7dade; - box-sizing: border-box; - left: 0; - pointer-events: none; - right: 0; - display: block; - height: 3px; - position: absolute; - margin-top: 14px; - top: 0; -} - -.emotion-4 { - background-color: currentColor; - border-radius: 1px; - box-sizing: border-box; - height: 3px; - pointer-events: none; - display: block; - position: absolute; - margin-top: 14px; - top: 0; -} - -.emotion-8 { - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - box-sizing: border-box; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - height: 20px; - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; - justify-content: center; - margin-top: 5px; - outline: 0; - pointer-events: none; - position: absolute; - top: 0; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - width: 20px; - margin-left: -10px; -} - -.emotion-6 { - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - background-color: white; - border-radius: 50%; - border: 1px solid #7e8993; - box-sizing: border-box; - height: 100%; - outline: 0; - pointer-events: none; - position: absolute; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - width: 100%; - border-color: #7e8993; - box-shadow: 0 0 0 rgba(0,0,0,0); -} - -.emotion-10 { - background: #23282d; - border-radius: 3px; - box-sizing: border-box; - color: white; - display: inline-block; - font-size: 11px; - min-width: 32px; - opacity: 0; - padding: 8px; - pointer-events: none; - position: absolute; - text-align: center; - -webkit-transition: opacity 120ms ease; - transition: opacity 120ms ease; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - opacity: 0; - margin-top: -4px; - top: -100%; - -webkit-transform: translateX(-50%); - -ms-transform: translateX(-50%); - transform: translateX(-50%); -} - -.emotion-10::after { - border: 6px solid #23282d; - border-left-color: transparent; - border-right-color: transparent; - bottom: -6px; - box-sizing: border-box; - content: ''; - height: 0; - left: 50%; - line-height: 0; - margin-left: -6px; - position: absolute; - width: 0; -} - -.emotion-10::after { - border-bottom: none; - border-top-style: solid; - bottom: -6px; -} - -@media ( prefers-reduced-motion:reduce ) { - .emotion-10 { - -webkit-transition-duration: 0ms; - transition-duration: 0ms; - } -} - -.emotion-14 { - margin-top: 3px; - margin-left: 16px; -} - -.emotion-16 { - box-sizing: border-box; - display: inline-block; - margin-top: 0; - min-width: 54px; - max-width: 120px; - margin-left: 16px; -} - -input[type='number'].emotion-16 { - height: 30px; - min-height: 30px; -} - -<div - className="components-base-control components-range-control" -> - <div - className="components-base-control__field" - > - <label - className="components-base-control__label" - htmlFor="inspector-range-control-6" - > - How many columns should this use? - </label> - <span - className="components-range-control__root emotion-18 emotion-19" - > - <span - className="components-range-control__wrapper emotion-12 emotion-13" - color="#00669b" - > - <input - aria-hidden={false} - aria-label="How many columns should this use?" - className="components-range-control__slider emotion-0 emotion-1" - disabled={false} - id="inspector-range-control-6" - max={100} - min={0} - onBlur={[Function]} - onChange={[Function]} - onFocus={[Function]} - onMouseLeave={[Function]} - onMouseMove={[Function]} - step={1} - tabIndex={0} - type="range" - value={5} - /> - <span - aria-hidden={true} - className="emotion-2 emotion-3" - disabled={false} - /> - <span - aria-hidden={true} - className="components-range-control__track emotion-4 emotion-5" - disabled={false} - style={ - Object { - "width": "5%", - } - } - /> - <span - className="emotion-8 emotion-9" - style={ - Object { - "left": "5%", - } - } - > - <span - aria-hidden={true} - className="emotion-6 emotion-7" - /> - </span> - <span - aria-hidden={false} - className="components-simple-tooltip components-range-control__tooltip emotion-10 emotion-11" - role="tooltip" - style={ - Object { - "left": "5%", - "zIndex": 100, - } - } - > - 5 - </span> - </span> - <span - className="emotion-14 emotion-15" - > - <svg - aria-hidden="true" - className="dashicon dashicons-wordpress" - focusable="false" - height={20} - role="img" - viewBox="0 0 20 20" - width={20} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M20 10c0-5.52-4.48-10-10-10S0 4.48 0 10s4.48 10 10 10 10-4.48 10-10zM10 1.01c4.97 0 8.99 4.02 8.99 8.99s-4.02 8.99-8.99 8.99S1.01 14.97 1.01 10 5.03 1.01 10 1.01zM8.01 14.82L4.96 6.61c.49-.03 1.05-.08 1.05-.08.43-.05.38-1.01-.06-.99 0 0-1.29.1-2.13.1-.15 0-.33 0-.52-.01 1.44-2.17 3.9-3.6 6.7-3.6 2.09 0 3.99.79 5.41 2.09-.6-.08-1.45.35-1.45 1.42 0 .66.38 1.22.79 1.88.31.54.5 1.22.5 2.21 0 1.34-1.27 4.48-1.27 4.48l-2.71-7.5c.48-.03.75-.16.75-.16.43-.05.38-1.1-.05-1.08 0 0-1.3.11-2.14.11-.78 0-2.11-.11-2.11-.11-.43-.02-.48 1.06-.05 1.08l.84.08 1.12 3.04zm6.02 2.15L16.64 10s.67-1.69.39-3.81c.63 1.14.94 2.42.94 3.81 0 2.96-1.56 5.58-3.94 6.97zM2.68 6.77L6.5 17.25c-2.67-1.3-4.47-4.08-4.47-7.25 0-1.16.2-2.23.65-3.23zm7.45 4.53l2.29 6.25c-.75.27-1.57.42-2.42.42-.72 0-1.41-.11-2.06-.3z" - /> - </svg> - </span> - <input - aria-label="How many columns should this use?" - className="components-range-control__number emotion-16 emotion-133" - disabled={false} - inputMode="decimal" - max={100} - min={0} - onChange={[Function]} - step={1} - type="number" - value={5} - /> - </span> - </div> -</div> -`; - -exports[`Storyshots Components/RangeControl With Icon Before 1`] = ` -.emotion-18 { - -webkit-tap-highlight-color: transparent; - box-sizing: border-box; - cursor: pointer; - -webkit-align-items: flex-start; - -webkit-box-align: flex-start; - -ms-flex-align: flex-start; - align-items: flex-start; - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; - -webkit-box-pack: start; - -webkit-justify-content: flex-start; - -ms-flex-pack: start; - justify-content: flex-start; - padding: 0; - position: relative; - touch-action: none; - width: 100%; -} - -.emotion-0 { - margin-top: 3px; - margin-right: 6px; -} - -.emotion-14 { - box-sizing: border-box; - color: #007cba; - display: block; - padding-top: 15px; - position: relative; - width: 100%; - height: 30px; - min-height: 30px; - margin-left: 10px; -} - -.emotion-2 { - box-sizing: border-box; - cursor: pointer; - display: block; - height: 100%; - left: 0; - margin: 0; - opacity: 0; - outline: none; - position: absolute; - right: 0; - top: 0; - width: 100%; -} - -.emotion-4 { - background-color: #d7dade; - box-sizing: border-box; - left: 0; - pointer-events: none; - right: 0; - display: block; - height: 3px; - position: absolute; - margin-top: 14px; - top: 0; -} - -.emotion-6 { - background-color: currentColor; - border-radius: 1px; - box-sizing: border-box; - height: 3px; - pointer-events: none; - display: block; - position: absolute; - margin-top: 14px; - top: 0; -} - -.emotion-10 { - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - box-sizing: border-box; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - height: 20px; - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; - justify-content: center; - margin-top: 5px; - outline: 0; - pointer-events: none; - position: absolute; - top: 0; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - width: 20px; - margin-left: -10px; -} - -.emotion-8 { - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - background-color: white; - border-radius: 50%; - border: 1px solid #7e8993; - box-sizing: border-box; - height: 100%; - outline: 0; - pointer-events: none; - position: absolute; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - width: 100%; - border-color: #7e8993; - box-shadow: 0 0 0 rgba(0,0,0,0); -} - -.emotion-12 { - background: #23282d; - border-radius: 3px; - box-sizing: border-box; - color: white; - display: inline-block; - font-size: 11px; - min-width: 32px; - opacity: 0; - padding: 8px; - pointer-events: none; - position: absolute; - text-align: center; - -webkit-transition: opacity 120ms ease; - transition: opacity 120ms ease; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - opacity: 0; - margin-top: -4px; - top: -100%; - -webkit-transform: translateX(-50%); - -ms-transform: translateX(-50%); - transform: translateX(-50%); -} - -.emotion-12::after { - border: 6px solid #23282d; - border-left-color: transparent; - border-right-color: transparent; - bottom: -6px; - box-sizing: border-box; - content: ''; - height: 0; - left: 50%; - line-height: 0; - margin-left: -6px; - position: absolute; - width: 0; -} - -.emotion-12::after { - border-bottom: none; - border-top-style: solid; - bottom: -6px; -} - -@media ( prefers-reduced-motion:reduce ) { - .emotion-12 { - -webkit-transition-duration: 0ms; - transition-duration: 0ms; - } -} - -.emotion-16 { - box-sizing: border-box; - display: inline-block; - margin-top: 0; - min-width: 54px; - max-width: 120px; - margin-left: 16px; -} - -input[type='number'].emotion-16 { - height: 30px; - min-height: 30px; -} - -<div - className="components-base-control components-range-control" -> - <div - className="components-base-control__field" - > - <label - className="components-base-control__label" - htmlFor="inspector-range-control-5" - > - How many columns should this use? - </label> - <span - className="components-range-control__root emotion-18 emotion-19" - > - <span - className="emotion-0 emotion-1" - > - <svg - aria-hidden="true" - className="dashicon dashicons-wordpress" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M20 10c0-5.52-4.48-10-10-10S0 4.48 0 10s4.48 10 10 10 10-4.48 10-10zM10 1.01c4.97 0 8.99 4.02 8.99 8.99s-4.02 8.99-8.99 8.99S1.01 14.97 1.01 10 5.03 1.01 10 1.01zM8.01 14.82L4.96 6.61c.49-.03 1.05-.08 1.05-.08.43-.05.38-1.01-.06-.99 0 0-1.29.1-2.13.1-.15 0-.33 0-.52-.01 1.44-2.17 3.9-3.6 6.7-3.6 2.09 0 3.99.79 5.41 2.09-.6-.08-1.45.35-1.45 1.42 0 .66.38 1.22.79 1.88.31.54.5 1.22.5 2.21 0 1.34-1.27 4.48-1.27 4.48l-2.71-7.5c.48-.03.75-.16.75-.16.43-.05.38-1.1-.05-1.08 0 0-1.3.11-2.14.11-.78 0-2.11-.11-2.11-.11-.43-.02-.48 1.06-.05 1.08l.84.08 1.12 3.04zm6.02 2.15L16.64 10s.67-1.69.39-3.81c.63 1.14.94 2.42.94 3.81 0 2.96-1.56 5.58-3.94 6.97zM2.68 6.77L6.5 17.25c-2.67-1.3-4.47-4.08-4.47-7.25 0-1.16.2-2.23.65-3.23zm7.45 4.53l2.29 6.25c-.75.27-1.57.42-2.42.42-.72 0-1.41-.11-2.06-.3z" - /> - </svg> - </span> - <span - className="components-range-control__wrapper emotion-14 emotion-15" - color="#00669b" - > - <input - aria-hidden={false} - aria-label="How many columns should this use?" - className="components-range-control__slider emotion-2 emotion-3" - disabled={false} - id="inspector-range-control-5" - max={100} - min={0} - onBlur={[Function]} - onChange={[Function]} - onFocus={[Function]} - onMouseLeave={[Function]} - onMouseMove={[Function]} - step={1} - tabIndex={0} - type="range" - value={5} - /> - <span - aria-hidden={true} - className="emotion-4 emotion-5" - disabled={false} - /> - <span - aria-hidden={true} - className="components-range-control__track emotion-6 emotion-7" - disabled={false} - style={ - Object { - "width": "5%", - } - } - /> - <span - className="emotion-10 emotion-11" - style={ - Object { - "left": "5%", - } - } - > - <span - aria-hidden={true} - className="emotion-8 emotion-9" - /> - </span> - <span - aria-hidden={false} - className="components-simple-tooltip components-range-control__tooltip emotion-12 emotion-13" - role="tooltip" - style={ - Object { - "left": "5%", - "zIndex": 100, - } - } - > - 5 - </span> - </span> - <input - aria-label="How many columns should this use?" - className="components-range-control__number emotion-16 emotion-153" - disabled={false} - inputMode="decimal" - max={100} - min={0} - onChange={[Function]} - step={1} - type="number" - value={5} - /> - </span> - </div> -</div> -`; - -exports[`Storyshots Components/RangeControl With Minimum And Maximum Limits 1`] = ` -.emotion-16 { - -webkit-tap-highlight-color: transparent; - box-sizing: border-box; - cursor: pointer; - -webkit-align-items: flex-start; - -webkit-box-align: flex-start; - -ms-flex-align: flex-start; - align-items: flex-start; - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; - -webkit-box-pack: start; - -webkit-justify-content: flex-start; - -ms-flex-pack: start; - justify-content: flex-start; - padding: 0; - position: relative; - touch-action: none; - width: 100%; -} - -.emotion-12 { - box-sizing: border-box; - color: #007cba; - display: block; - padding-top: 15px; - position: relative; - width: 100%; - height: 30px; - min-height: 30px; - margin-left: 10px; -} - -.emotion-0 { - box-sizing: border-box; - cursor: pointer; - display: block; - height: 100%; - left: 0; - margin: 0; - opacity: 0; - outline: none; - position: absolute; - right: 0; - top: 0; - width: 100%; -} - -.emotion-2 { - background-color: #d7dade; - box-sizing: border-box; - left: 0; - pointer-events: none; - right: 0; - display: block; - height: 3px; - position: absolute; - margin-top: 14px; - top: 0; -} - -.emotion-4 { - background-color: currentColor; - border-radius: 1px; - box-sizing: border-box; - height: 3px; - pointer-events: none; - display: block; - position: absolute; - margin-top: 14px; - top: 0; -} - -.emotion-8 { - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - box-sizing: border-box; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - height: 20px; - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; - justify-content: center; - margin-top: 5px; - outline: 0; - pointer-events: none; - position: absolute; - top: 0; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - width: 20px; - margin-left: -10px; -} - -.emotion-6 { - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - background-color: white; - border-radius: 50%; - border: 1px solid #7e8993; - box-sizing: border-box; - height: 100%; - outline: 0; - pointer-events: none; - position: absolute; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - width: 100%; - border-color: #7e8993; - box-shadow: 0 0 0 rgba(0,0,0,0); -} - -.emotion-10 { - background: #23282d; - border-radius: 3px; - box-sizing: border-box; - color: white; - display: inline-block; - font-size: 11px; - min-width: 32px; - opacity: 0; - padding: 8px; - pointer-events: none; - position: absolute; - text-align: center; - -webkit-transition: opacity 120ms ease; - transition: opacity 120ms ease; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - opacity: 0; - margin-top: -4px; - top: -100%; - -webkit-transform: translateX(-50%); - -ms-transform: translateX(-50%); - transform: translateX(-50%); -} - -.emotion-10::after { - border: 6px solid #23282d; - border-left-color: transparent; - border-right-color: transparent; - bottom: -6px; - box-sizing: border-box; - content: ''; - height: 0; - left: 50%; - line-height: 0; - margin-left: -6px; - position: absolute; - width: 0; -} - -.emotion-10::after { - border-bottom: none; - border-top-style: solid; - bottom: -6px; -} - -@media ( prefers-reduced-motion:reduce ) { - .emotion-10 { - -webkit-transition-duration: 0ms; - transition-duration: 0ms; - } -} - -.emotion-14 { - box-sizing: border-box; - display: inline-block; - margin-top: 0; - min-width: 54px; - max-width: 120px; - margin-left: 16px; -} - -input[type='number'].emotion-14 { - height: 30px; - min-height: 30px; -} - -<div - className="components-base-control components-range-control" -> - <div - className="components-base-control__field" - > - <label - className="components-base-control__label" - htmlFor="inspector-range-control-4" - > - How many columns should this use? - </label> - <span - className="components-range-control__root emotion-16 emotion-17" - > - <span - className="components-range-control__wrapper emotion-12 emotion-13" - color="#00669b" - > - <input - aria-hidden={false} - aria-label="How many columns should this use?" - className="components-range-control__slider emotion-0 emotion-1" - disabled={false} - id="inspector-range-control-4" - max={10} - min={2} - onBlur={[Function]} - onChange={[Function]} - onFocus={[Function]} - onMouseLeave={[Function]} - onMouseMove={[Function]} - step={1} - tabIndex={0} - type="range" - value={5} - /> - <span - aria-hidden={true} - className="emotion-2 emotion-3" - disabled={false} - /> - <span - aria-hidden={true} - className="components-range-control__track emotion-4 emotion-5" - disabled={false} - style={ - Object { - "width": "37.5%", - } - } - /> - <span - className="emotion-8 emotion-9" - style={ - Object { - "left": "37.5%", - } - } - > - <span - aria-hidden={true} - className="emotion-6 emotion-7" - /> - </span> - <span - aria-hidden={false} - className="components-simple-tooltip components-range-control__tooltip emotion-10 emotion-11" - role="tooltip" - style={ - Object { - "left": "37.5%", - "zIndex": 100, - } - } - > - 5 - </span> - </span> - <input - aria-label="How many columns should this use?" - className="components-range-control__number emotion-14 emotion-133" - disabled={false} - inputMode="decimal" - max={10} - min={2} - onChange={[Function]} - step={1} - type="number" - value={5} - /> - </span> - </div> -</div> -`; - -exports[`Storyshots Components/RangeControl With Reset 1`] = ` -.emotion-18 { - -webkit-tap-highlight-color: transparent; - box-sizing: border-box; - cursor: pointer; - -webkit-align-items: flex-start; - -webkit-box-align: flex-start; - -ms-flex-align: flex-start; - align-items: flex-start; - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; - -webkit-box-pack: start; - -webkit-justify-content: flex-start; - -ms-flex-pack: start; - justify-content: flex-start; - padding: 0; - position: relative; - touch-action: none; - width: 100%; -} - -.emotion-12 { - box-sizing: border-box; - color: #007cba; - display: block; - padding-top: 15px; - position: relative; - width: 100%; - height: 30px; - min-height: 30px; - margin-left: 10px; -} - -.emotion-0 { - box-sizing: border-box; - cursor: pointer; - display: block; - height: 100%; - left: 0; - margin: 0; - opacity: 0; - outline: none; - position: absolute; - right: 0; - top: 0; - width: 100%; -} - -.emotion-2 { - background-color: #d7dade; - box-sizing: border-box; - left: 0; - pointer-events: none; - right: 0; - display: block; - height: 3px; - position: absolute; - margin-top: 14px; - top: 0; -} - -.emotion-4 { - background-color: currentColor; - border-radius: 1px; - box-sizing: border-box; - height: 3px; - pointer-events: none; - display: block; - position: absolute; - margin-top: 14px; - top: 0; -} - -.emotion-8 { - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - box-sizing: border-box; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - height: 20px; - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; - justify-content: center; - margin-top: 5px; - outline: 0; - pointer-events: none; - position: absolute; - top: 0; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - width: 20px; - margin-left: -10px; -} - -.emotion-6 { - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - background-color: white; - border-radius: 50%; - border: 1px solid #7e8993; - box-sizing: border-box; - height: 100%; - outline: 0; - pointer-events: none; - position: absolute; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - width: 100%; - border-color: #7e8993; - box-shadow: 0 0 0 rgba(0,0,0,0); -} - -.emotion-10 { - background: #23282d; - border-radius: 3px; - box-sizing: border-box; - color: white; - display: inline-block; - font-size: 11px; - min-width: 32px; - opacity: 0; - padding: 8px; - pointer-events: none; - position: absolute; - text-align: center; - -webkit-transition: opacity 120ms ease; - transition: opacity 120ms ease; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - opacity: 0; - margin-top: -4px; - top: -100%; - -webkit-transform: translateX(-50%); - -ms-transform: translateX(-50%); - transform: translateX(-50%); -} - -.emotion-10::after { - border: 6px solid #23282d; - border-left-color: transparent; - border-right-color: transparent; - bottom: -6px; - box-sizing: border-box; - content: ''; - height: 0; - left: 50%; - line-height: 0; - margin-left: -6px; - position: absolute; - width: 0; -} - -.emotion-10::after { - border-bottom: none; - border-top-style: solid; - bottom: -6px; -} - -@media ( prefers-reduced-motion:reduce ) { - .emotion-10 { - -webkit-transition-duration: 0ms; - transition-duration: 0ms; - } -} - -.emotion-14 { - box-sizing: border-box; - display: inline-block; - margin-top: 0; - min-width: 54px; - max-width: 120px; - margin-left: 16px; -} - -input[type='number'].emotion-14 { - height: 30px; - min-height: 30px; -} - -.emotion-16 { - box-sizing: border-box; - display: block; - margin-top: 0; - margin-left: 8px; -} - -.emotion-16 button, -.emotion-16 button.is-small { - margin-left: 0; - height: 30px; - min-height: 30px; -} - -<div - className="components-base-control components-range-control" -> - <div - className="components-base-control__field" - > - <label - className="components-base-control__label" - htmlFor="inspector-range-control-7" - > - How many columns should this use? - </label> - <span - className="components-range-control__root emotion-18 emotion-19" - > - <span - className="components-range-control__wrapper emotion-12 emotion-13" - color="#00669b" - > - <input - aria-hidden={false} - aria-label="How many columns should this use?" - className="components-range-control__slider emotion-0 emotion-1" - disabled={false} - id="inspector-range-control-7" - max={100} - min={0} - onBlur={[Function]} - onChange={[Function]} - onFocus={[Function]} - onMouseLeave={[Function]} - onMouseMove={[Function]} - step={1} - tabIndex={0} - type="range" - value={5} - /> - <span - aria-hidden={true} - className="emotion-2 emotion-3" - disabled={false} - /> - <span - aria-hidden={true} - className="components-range-control__track emotion-4 emotion-5" - disabled={false} - style={ - Object { - "width": "5%", - } - } - /> - <span - className="emotion-8 emotion-9" - style={ - Object { - "left": "5%", - } - } - > - <span - aria-hidden={true} - className="emotion-6 emotion-7" - /> - </span> - <span - aria-hidden={false} - className="components-simple-tooltip components-range-control__tooltip emotion-10 emotion-11" - role="tooltip" - style={ - Object { - "left": "5%", - "zIndex": 100, - } - } - > - 5 - </span> - </span> - <input - aria-label="How many columns should this use?" - className="components-range-control__number emotion-14 emotion-133" - disabled={false} - inputMode="decimal" - max={100} - min={0} - onChange={[Function]} - step={1} - type="number" - value={5} - /> - <span - className="emotion-16 emotion-134" - > - <button - className="components-button components-range-control__reset is-secondary is-small" - disabled={false} - onClick={[Function]} - type="button" - > - Reset - </button> - </span> - </span> - </div> -</div> -`; - -exports[`Storyshots Components/ResizableBox Default 1`] = ` -<div - style={ - Object { - "margin": 30, - } - } -> - <div - className="components-resizable-box__container has-show-handle" - style={ - Object { - "boxSizing": "border-box", - "height": "200px", - "maxHeight": undefined, - "maxWidth": undefined, - "minHeight": 50, - "minWidth": 50, - "position": "relative", - "userSelect": "auto", - "width": "400px", - } - } - > - <div - style={ - Object { - "alignItems": "center", - "background": "#eee", - "display": "flex", - "height": "100%", - "justifyContent": "center", - "width": "100%", - } - } - > - <span> - Resize - </span> - </div> - <span> - <div - className="components-resizable-box__handle components-resizable-box__side-handle components-resizable-box__handle-right" - onMouseDown={[Function]} - onTouchStart={[Function]} - style={ - Object { - "bottom": null, - "cursor": "col-resize", - "height": null, - "left": null, - "position": "absolute", - "right": null, - "top": null, - "userSelect": "none", - "width": null, - } - } - /> - <div - className="components-resizable-box__handle components-resizable-box__side-handle components-resizable-box__handle-bottom" - onMouseDown={[Function]} - onTouchStart={[Function]} - style={ - Object { - "bottom": null, - "cursor": "row-resize", - "height": null, - "left": null, - "position": "absolute", - "right": null, - "top": null, - "userSelect": "none", - "width": null, - } - } - /> - <div - className="components-resizable-box__handle components-resizable-box__corner-handle components-resizable-box__handle-bottom components-resizable-box__handle-right" - onMouseDown={[Function]} - onTouchStart={[Function]} - style={ - Object { - "bottom": null, - "cursor": "se-resize", - "height": null, - "left": null, - "position": "absolute", - "right": null, - "top": null, - "userSelect": "none", - "width": null, - } - } - /> - </span> - </div> -</div> -`; - -exports[`Storyshots Components/ScrollLock Default 1`] = ` -<div - style={ - Object { - "backgroundColor": "#fff", - "backgroundImage": "linear-gradient(transparent 50%, rgba(0, 0, 0, 0.05) 50%)", - "backgroundSize": "50px 50px", - "height": 3000, - "position": "relative", - } - } -> - <div> - Start scrolling down... - </div> - <div - style={ - Object { - "display": "flex", - "justifyContent": "center", - "padding": 40, - "position": "sticky", - "textAlign": "center", - "top": 0, - } - } - > - <div> - <button - className="components-button is-secondary" - onClick={[Function]} - type="button" - > - Toggle Scroll Lock - </button> - <p> - Scroll locked: - - <strong> - No - </strong> - </p> - </div> - </div> -</div> -`; - -exports[`Storyshots Components/SelectControl Default 1`] = ` -<div - className="components-base-control" -> - <div - className="components-base-control__field" - > - <label - className="components-base-control__label" - htmlFor="inspector-select-control-0" - > - Label Text - </label> - <select - aria-describedby="inspector-select-control-0__help" - className="components-select-control__input" - id="inspector-select-control-0" - multiple={false} - onChange={[Function]} - > - <option - disabled={true} - value={null} - > - Select an Option - </option> - <option - value="a" - > - Option A - </option> - <option - value="b" - > - Option B - </option> - <option - value="c" - > - Option C - </option> - </select> - </div> - <p - className="components-base-control__help" - id="inspector-select-control-0__help" - > - Help text to explain the select control. - </p> -</div> -`; - -exports[`Storyshots Components/Snackbar Default 1`] = ` -<div - className="components-snackbar" - label="Dismiss this notice" - onClick={[Function]} - onKeyPress={[Function]} - role="button" - tabIndex="0" -> - <div - className="components-snackbar__content" - > - Use Snackbars to communicate low priority, non-interruptive messages to the user. - </div> -</div> -`; - -exports[`Storyshots Components/Snackbar With Actions 1`] = ` -<div - className="components-snackbar" - label="Dismiss this notice" - onClick={[Function]} - onKeyPress={[Function]} - role="button" - tabIndex="0" -> - <div - className="components-snackbar__content" - > - Use Snackbars with an action link to an external page. - <a - className="components-button components-snackbar__action is-tertiary" - href="https://wordpress.org" - onClick={[Function]} - > - Open WP.org - </a> - </div> -</div> -`; - -exports[`Storyshots Components/Spinner Default 1`] = ` -<span - className="components-spinner" -/> -`; - -exports[`Storyshots Components/TabPanel Default 1`] = ` -<div - className="my-tab-panel" -> - <div - aria-orientation="horizontal" - className="components-tab-panel__tabs" - role="tablist" - > - <button - aria-controls="0-tab1-view" - aria-selected={true} - className="components-button components-tab-panel__tabs-item tab-one is-active" - id="0-tab1" - onClick={[Function]} - role="tab" - tabIndex={null} - type="button" - > - Tab 1 - </button> - <button - aria-controls="0-tab2-view" - aria-selected={false} - className="components-button components-tab-panel__tabs-item tab-two" - id="0-tab2" - onClick={[Function]} - role="tab" - tabIndex={-1} - type="button" - > - Tab 2 - </button> - </div> - <div - aria-labelledby="0-tab1" - className="components-tab-panel__tab-content" - id="0-tab1-view" - role="tabpanel" - tabIndex="0" - > - <p> - Selected tab: - Tab 1 - </p> - </div> -</div> -`; - -exports[`Storyshots Components/TextControl Default 1`] = ` -<div - className="components-base-control" -> - <div - className="components-base-control__field" - > - <label - className="components-base-control__label" - htmlFor="inspector-text-control-3" - > - Label Text - </label> - <input - aria-describedby="inspector-text-control-3__help" - className="components-text-control__input" - id="inspector-text-control-3" - onChange={[Function]} - type="text" - /> - </div> - <p - className="components-base-control__help" - id="inspector-text-control-3__help" - > - Help text to explain the input. - </p> -</div> -`; - -exports[`Storyshots Components/TextHighlight Default 1`] = ` -Array [ - "We call the new editor ", - <mark> - Gutenberg - </mark>, - ". The entire editing experience has been rebuilt for media rich pages and posts.", -] -`; - -exports[`Storyshots Components/TextareaControl Default 1`] = ` -<div - className="components-base-control" -> - <div - className="components-base-control__field" - > - <label - className="components-base-control__label" - htmlFor="inspector-textarea-control-0" - > - Label Text - </label> - <textarea - aria-describedby="inspector-textarea-control-0__help" - className="components-textarea-control__input" - id="inspector-textarea-control-0" - onChange={[Function]} - rows={4} - /> - </div> - <p - className="components-base-control__help" - id="inspector-textarea-control-0__help" - > - Help text to explain the textarea. - </p> -</div> -`; - -exports[`Storyshots Components/Tip Default 1`] = ` -<div - className="components-tip" -> - <svg - aria-hidden="true" - focusable="false" - height="24" - role="img" - viewBox="0 0 24 24" - width="24" - > - <path - d="M12 15.8c-3.7 0-6.8-3-6.8-6.8s3-6.8 6.8-6.8c3.7 0 6.8 3 6.8 6.8s-3.1 6.8-6.8 6.8zm0-12C9.1 3.8 6.8 6.1 6.8 9s2.4 5.2 5.2 5.2c2.9 0 5.2-2.4 5.2-5.2S14.9 3.8 12 3.8zM8 17.5h8V19H8zM10 20.5h4V22h-4z" - /> - </svg> - <p> - <p> - An example tip - </p> - </p> -</div> -`; - -exports[`Storyshots Components/ToggleControl Default 1`] = ` -<div - className="components-base-control components-toggle-control" -> - <div - className="components-base-control__field" - > - <span - className="components-form-toggle is-checked" - > - <input - checked={true} - className="components-form-toggle__input" - id="inspector-toggle-control-0" - onChange={[Function]} - type="checkbox" - /> - <span - className="components-form-toggle__track" - /> - <span - className="components-form-toggle__thumb" - /> - <svg - aria-hidden="true" - className="components-form-toggle__on" - focusable="false" - height="6" - role="img" - viewBox="0 0 2 6" - width="2" - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M0 0h2v6H0z" - /> - </svg> - </span> - <label - className="components-toggle-control__label" - htmlFor="inspector-toggle-control-0" - > - Does this have a fixed background? - </label> - </div> -</div> -`; - -exports[`Storyshots Components/ToggleControl With Help Text 1`] = ` -<div - className="components-base-control components-toggle-control" -> - <div - className="components-base-control__field" - > - <span - className="components-form-toggle is-checked" - > - <input - aria-describedby="inspector-toggle-control-1__help" - checked={true} - className="components-form-toggle__input" - id="inspector-toggle-control-1" - onChange={[Function]} - type="checkbox" - /> - <span - className="components-form-toggle__track" - /> - <span - className="components-form-toggle__thumb" - /> - <svg - aria-hidden="true" - className="components-form-toggle__on" - focusable="false" - height="6" - role="img" - viewBox="0 0 2 6" - width="2" - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M0 0h2v6H0z" - /> - </svg> - </span> - <label - className="components-toggle-control__label" - htmlFor="inspector-toggle-control-1" - > - Does this have a fixed background? - </label> - </div> - <p - className="components-base-control__help" - id="inspector-toggle-control-1__help" - > - Has fixed background. - </p> -</div> -`; - -exports[`Storyshots Components/ToolTip Default 1`] = ` -<div - onBlur={[Function]} - onClick={[Function]} - onFocus={[Function]} - onMouseDown={[Function]} - onMouseEnter={[Function]} - onMouseLeave={[Function]} - style={ - Object { - "border": "1px solid #ccc", - "margin": "50px auto", - "padding": "20px", - "textAlign": "center", - "width": "200px", - } - } -> - Hover for more information -</div> -`; - -exports[`Storyshots Components/Toolbar Default 1`] = ` -<div - aria-label="Options" - aria-orientation="horizontal" - className="components-accessible-toolbar" - id="options-toolbar" - role="toolbar" -> - <div - className="components-toolbar-group" - > - <button - aria-label="Paragraph" - className="components-button components-toolbar-button has-icon" - id="options-toolbar-1" - onBlur={[Function]} - onClick={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onMouseDown={[Function]} - onMouseEnter={[Function]} - onMouseLeave={[Function]} - tabIndex={-1} - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18.3 4H9.9v-.1l-.9.2c-2.3.4-4 2.4-4 4.8s1.7 4.4 4 4.8l.7.1V20h1.5V5.5h2.9V20h1.5V5.5h2.7V4z" - /> - </svg> - </button> - </div> - <div - className="components-toolbar-group" - > - <div - className="components-dropdown components-dropdown-menu" - > - <button - aria-expanded={false} - aria-haspopup="true" - aria-label="Change text alignment" - className="components-button components-dropdown-menu__toggle has-icon" - id="options-toolbar-2" - onBlur={[Function]} - onClick={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onMouseDown={[Function]} - onMouseEnter={[Function]} - onMouseLeave={[Function]} - tabIndex={-1} - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 19.8h8.9v-1.5H4v1.5zm8.9-15.6H4v1.5h8.9V4.2zm-8.9 7v1.5h16v-1.5H4z" - /> - </svg> - </button> - </div> - </div> - <div - className="components-toolbar-group" - > - <button - className="components-button components-toolbar-button" - id="options-toolbar-3" - onClick={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onMouseDown={[Function]} - tabIndex={-1} - type="button" - > - Text - </button> - <button - aria-label="Bold" - aria-pressed={true} - className="components-button components-toolbar-button is-pressed has-icon" - id="options-toolbar-4" - onBlur={[Function]} - onClick={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onMouseDown={[Function]} - onMouseEnter={[Function]} - onMouseLeave={[Function]} - tabIndex={-1} - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M14.7 11.3c1-.6 1.5-1.6 1.5-3 0-2.3-1.3-3.4-4-3.4H7v14h5.8c1.4 0 2.5-.3 3.3-1 .8-.7 1.2-1.7 1.2-2.9.1-1.9-.8-3.1-2.6-3.7zm-5.1-4h2.3c.6 0 1.1.1 1.4.4.3.3.5.7.5 1.2s-.2 1-.5 1.2c-.3.3-.8.4-1.4.4H9.6V7.3zm4.6 9c-.4.3-1 .4-1.7.4H9.6v-3.9h2.9c.7 0 1.3.2 1.7.5.4.3.6.8.6 1.5s-.2 1.2-.6 1.5z" - /> - </svg> - </button> - <button - aria-label="Italic" - className="components-button components-toolbar-button has-icon" - id="options-toolbar-5" - onBlur={[Function]} - onClick={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onMouseDown={[Function]} - onMouseEnter={[Function]} - onMouseLeave={[Function]} - tabIndex={-1} - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M12.5 5L10 19h1.9l2.5-14z" - /> - </svg> - </button> - <button - aria-label="Link" - className="components-button components-toolbar-button has-icon" - id="options-toolbar-6" - onBlur={[Function]} - onClick={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onMouseDown={[Function]} - onMouseEnter={[Function]} - onMouseLeave={[Function]} - tabIndex={-1} - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M15.6 7.2H14v1.5h1.6c2 0 3.7 1.7 3.7 3.7s-1.7 3.7-3.7 3.7H14v1.5h1.6c2.8 0 5.2-2.3 5.2-5.2 0-2.9-2.3-5.2-5.2-5.2zM4.7 12.4c0-2 1.7-3.7 3.7-3.7H10V7.2H8.4c-2.9 0-5.2 2.3-5.2 5.2 0 2.9 2.3 5.2 5.2 5.2H10v-1.5H8.4c-2 0-3.7-1.7-3.7-3.7zm4.6.9h5.3v-1.5H9.3v1.5z" - /> - </svg> - </button> - <div - className="components-dropdown components-dropdown-menu components-toolbar-group" - > - <button - aria-expanded={false} - aria-haspopup="true" - aria-label="More rich text controls" - className="components-button components-dropdown-menu__toggle" - id="options-toolbar-7" - onBlur={[Function]} - onClick={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onMouseDown={[Function]} - onMouseEnter={[Function]} - onMouseLeave={[Function]} - tabIndex={-1} - type="button" - /> - </div> - </div> - <div - className="components-dropdown components-dropdown-menu components-toolbar-group" - > - <button - aria-expanded={false} - aria-haspopup="true" - aria-label="Change text alignment" - className="components-button components-dropdown-menu__toggle has-icon" - id="options-toolbar-8" - onBlur={[Function]} - onClick={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onMouseDown={[Function]} - onMouseEnter={[Function]} - onMouseLeave={[Function]} - tabIndex={-1} - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 9v1.5h16V9H4zm12 5.5h4V13h-4v1.5zm-6 0h4V13h-4v1.5zm-6 0h4V13H4v1.5z" - /> - </svg> - </button> - </div> -</div> -`; - -exports[`Storyshots Components/Toolbar Without Group 1`] = ` -<div - aria-label="Options" - aria-orientation="horizontal" - className="components-accessible-toolbar" - id="options-toolbar-without-group" - role="toolbar" -> - <button - aria-label="Bold" - aria-pressed={true} - className="components-button components-toolbar-button is-pressed has-icon" - id="options-toolbar-without-group-1" - onBlur={[Function]} - onClick={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onMouseDown={[Function]} - onMouseEnter={[Function]} - onMouseLeave={[Function]} - tabIndex={-1} - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M14.7 11.3c1-.6 1.5-1.6 1.5-3 0-2.3-1.3-3.4-4-3.4H7v14h5.8c1.4 0 2.5-.3 3.3-1 .8-.7 1.2-1.7 1.2-2.9.1-1.9-.8-3.1-2.6-3.7zm-5.1-4h2.3c.6 0 1.1.1 1.4.4.3.3.5.7.5 1.2s-.2 1-.5 1.2c-.3.3-.8.4-1.4.4H9.6V7.3zm4.6 9c-.4.3-1 .4-1.7.4H9.6v-3.9h2.9c.7 0 1.3.2 1.7.5.4.3.6.8.6 1.5s-.2 1.2-.6 1.5z" - /> - </svg> - </button> - <button - aria-label="Italic" - className="components-button components-toolbar-button has-icon" - id="options-toolbar-without-group-2" - onBlur={[Function]} - onClick={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onMouseDown={[Function]} - onMouseEnter={[Function]} - onMouseLeave={[Function]} - tabIndex={-1} - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M12.5 5L10 19h1.9l2.5-14z" - /> - </svg> - </button> - <button - aria-label="Link" - className="components-button components-toolbar-button has-icon" - id="options-toolbar-without-group-3" - onBlur={[Function]} - onClick={[Function]} - onFocus={[Function]} - onKeyDown={[Function]} - onMouseDown={[Function]} - onMouseEnter={[Function]} - onMouseLeave={[Function]} - tabIndex={-1} - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M15.6 7.2H14v1.5h1.6c2 0 3.7 1.7 3.7 3.7s-1.7 3.7-3.7 3.7H14v1.5h1.6c2.8 0 5.2-2.3 5.2-5.2 0-2.9-2.3-5.2-5.2-5.2zM4.7 12.4c0-2 1.7-3.7 3.7-3.7H10V7.2H8.4c-2.9 0-5.2 2.3-5.2 5.2 0 2.9 2.3 5.2 5.2 5.2H10v-1.5H8.4c-2 0-3.7-1.7-3.7-3.7zm4.6.9h5.3v-1.5H9.3v1.5z" - /> - </svg> - </button> -</div> -`; - -exports[`Storyshots Components/ToolbarGroup Default 1`] = ` -<div - className="components-toolbar" -> - <div> - <button - aria-label="Bold" - aria-pressed={true} - className="components-button components-toolbar__control is-pressed has-icon" - onBlur={[Function]} - onClick={[Function]} - onFocus={[Function]} - onMouseDown={[Function]} - onMouseEnter={[Function]} - onMouseLeave={[Function]} - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M14.7 11.3c1-.6 1.5-1.6 1.5-3 0-2.3-1.3-3.4-4-3.4H7v14h5.8c1.4 0 2.5-.3 3.3-1 .8-.7 1.2-1.7 1.2-2.9.1-1.9-.8-3.1-2.6-3.7zm-5.1-4h2.3c.6 0 1.1.1 1.4.4.3.3.5.7.5 1.2s-.2 1-.5 1.2c-.3.3-.8.4-1.4.4H9.6V7.3zm4.6 9c-.4.3-1 .4-1.7.4H9.6v-3.9h2.9c.7 0 1.3.2 1.7.5.4.3.6.8.6 1.5s-.2 1.2-.6 1.5z" - /> - </svg> - </button> - </div> - <div> - <button - aria-label="Italic" - className="components-button components-toolbar__control has-icon" - onBlur={[Function]} - onClick={[Function]} - onFocus={[Function]} - onMouseDown={[Function]} - onMouseEnter={[Function]} - onMouseLeave={[Function]} - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M12.5 5L10 19h1.9l2.5-14z" - /> - </svg> - </button> - </div> - <div> - <button - aria-label="Link" - className="components-button components-toolbar__control has-icon" - onBlur={[Function]} - onClick={[Function]} - onFocus={[Function]} - onMouseDown={[Function]} - onMouseEnter={[Function]} - onMouseLeave={[Function]} - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M15.6 7.2H14v1.5h1.6c2 0 3.7 1.7 3.7 3.7s-1.7 3.7-3.7 3.7H14v1.5h1.6c2.8 0 5.2-2.3 5.2-5.2 0-2.9-2.3-5.2-5.2-5.2zM4.7 12.4c0-2 1.7-3.7 3.7-3.7H10V7.2H8.4c-2.9 0-5.2 2.3-5.2 5.2 0 2.9 2.3 5.2 5.2 5.2H10v-1.5H8.4c-2 0-3.7-1.7-3.7-3.7zm4.6.9h5.3v-1.5H9.3v1.5z" - /> - </svg> - </button> - </div> -</div> -`; - -exports[`Storyshots Components/ToolbarGroup With Controls Prop 1`] = ` -<div - className="components-toolbar" -> - <div - className={null} - > - <button - aria-label="Bold" - aria-pressed={true} - className="components-button components-toolbar__control is-pressed has-icon" - onBlur={[Function]} - onClick={[Function]} - onFocus={[Function]} - onMouseDown={[Function]} - onMouseEnter={[Function]} - onMouseLeave={[Function]} - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M14.7 11.3c1-.6 1.5-1.6 1.5-3 0-2.3-1.3-3.4-4-3.4H7v14h5.8c1.4 0 2.5-.3 3.3-1 .8-.7 1.2-1.7 1.2-2.9.1-1.9-.8-3.1-2.6-3.7zm-5.1-4h2.3c.6 0 1.1.1 1.4.4.3.3.5.7.5 1.2s-.2 1-.5 1.2c-.3.3-.8.4-1.4.4H9.6V7.3zm4.6 9c-.4.3-1 .4-1.7.4H9.6v-3.9h2.9c.7 0 1.3.2 1.7.5.4.3.6.8.6 1.5s-.2 1.2-.6 1.5z" - /> - </svg> - </button> - </div> - <div - className={null} - > - <button - aria-label="Italic" - className="components-button components-toolbar__control has-icon" - onBlur={[Function]} - onClick={[Function]} - onFocus={[Function]} - onMouseDown={[Function]} - onMouseEnter={[Function]} - onMouseLeave={[Function]} - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M12.5 5L10 19h1.9l2.5-14z" - /> - </svg> - </button> - </div> - <div - className={null} - > - <button - aria-label="Link" - className="components-button components-toolbar__control has-icon" - onBlur={[Function]} - onClick={[Function]} - onFocus={[Function]} - onMouseDown={[Function]} - onMouseEnter={[Function]} - onMouseLeave={[Function]} - type="button" - > - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M15.6 7.2H14v1.5h1.6c2 0 3.7 1.7 3.7 3.7s-1.7 3.7-3.7 3.7H14v1.5h1.6c2.8 0 5.2-2.3 5.2-5.2 0-2.9-2.3-5.2-5.2-5.2zM4.7 12.4c0-2 1.7-3.7 3.7-3.7H10V7.2H8.4c-2.9 0-5.2 2.3-5.2 5.2 0 2.9 2.3 5.2 5.2 5.2H10v-1.5H8.4c-2 0-3.7-1.7-3.7-3.7zm4.6.9h5.3v-1.5H9.3v1.5z" - /> - </svg> - </button> - </div> -</div> -`; - -exports[`Storyshots Components/VisuallyHidden Default 1`] = ` -Array [ - <div - className="components-visually-hidden" - > - This should not show. - </div>, - <div> - This text will - - <span - className="components-visually-hidden" - > - but not inline - </span> - always show. - </div>, -] -`; - -exports[`Storyshots Components/VisuallyHidden With Additional Class Names 1`] = ` -Array [ - "Additional class names passed to VisuallyHidden extend the component class name.", - " ", - <label - className="components-visually-hidden test-input" - > - Check out my class! - - </label>, - "Inspect the HTML to see!", -] -`; - -exports[`Storyshots Components/VisuallyHidden With Forwarded Props 1`] = ` -Array [ - "Additional props can be passed to VisuallyHidden and are forwarded to the rendered element.", - " ", - <span - className="components-visually-hidden" - data-id="test" - > - Check out my data attribute! - - </span>, - "Inspect the HTML to see!", -] -`; - -exports[`Storyshots Components|AnglePicker Default 1`] = ` -<div - className="components-base-control components-angle-picker" -> - <div - className="components-base-control__field" - > - <label - className="components-base-control__label" - htmlFor="components-angle-picker__input-0" - > - Angle - </label> - <div - aria-hidden="true" - className="components-angle-picker__angle-circle" - onMouseDown={[Function]} - > - <div - className="components-angle-picker__angle-circle-indicator-wrapper" - > - <span - className="components-angle-picker__angle-circle-indicator" - /> - </div> - </div> - <input - className="components-angle-picker__input-field" - id="components-angle-picker__input-0" - max={360} - min={0} - onChange={[Function]} - step="1" - type="number" - /> - </div> -</div> -`; - -exports[`Storyshots Components|AnglePickerControl Default 1`] = ` -<div - className="components-base-control components-angle-picker-control" -> - <div - className="components-base-control__field" - > - <label - className="components-base-control__label" - htmlFor="components-angle-picker-control__input-0" - > - Angle - </label> - <div - aria-hidden="true" - className="components-angle-picker-control__angle-circle" - onMouseDown={[Function]} - > - <div - className="components-angle-picker-control__angle-circle-indicator-wrapper" - > - <span - className="components-angle-picker-control__angle-circle-indicator" - /> - </div> - </div> - <input - className="components-angle-picker-control__input-field" - id="components-angle-picker-control__input-0" - max={360} - min={0} - onChange={[Function]} - step="1" - type="number" - /> - </div> -</div> -`; - -exports[`Storyshots Icons/Icon Default 1`] = ` -Array [ - <div> - <h2> - Dashicons (corrected viewport) - </h2> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9 18.6L3.5 13l1-1L9 16.4l9.5-9.9 1 1z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9 18.6L3.5 13l1-1L9 16.4l9.5-9.9 1 1z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9 18.6L3.5 13l1-1L9 16.4l9.5-9.9 1 1z" - /> - </svg> - </div>, - <div> - <h2> - Material and Other - </h2> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18.3 4H9.9v-.1l-.9.2c-2.3.4-4 2.4-4 4.8s1.7 4.4 4 4.8l.7.1V20h1.5V5.5h2.9V20h1.5V5.5h2.7V4z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18.3 4H9.9v-.1l-.9.2c-2.3.4-4 2.4-4 4.8s1.7 4.4 4 4.8l.7.1V20h1.5V5.5h2.9V20h1.5V5.5h2.7V4z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18.3 4H9.9v-.1l-.9.2c-2.3.4-4 2.4-4 4.8s1.7 4.4 4 4.8l.7.1V20h1.5V5.5h2.9V20h1.5V5.5h2.7V4z" - /> - </svg> - </div>, -] -`; - -exports[`Storyshots Icons/Icon Library 1`] = ` -<div - style={ - Object { - "padding": "20px", - } - } -> - <label - htmlFor="filter-icon" - style={ - Object { - "paddingRight": "10px", - } - } - > - Filter Icons - </label> - <input - id="filter-icons" - onChange={[Function]} - placeholder="Icon name" - type="search" - value="" - /> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - alignCenter - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M16.4 4.2H7.6v1.5h8.9V4.2zM4 11.2v1.5h16v-1.5H4zm3.6 8.6h8.9v-1.5H7.6v1.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M16.4 4.2H7.6v1.5h8.9V4.2zM4 11.2v1.5h16v-1.5H4zm3.6 8.6h8.9v-1.5H7.6v1.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M16.4 4.2H7.6v1.5h8.9V4.2zM4 11.2v1.5h16v-1.5H4zm3.6 8.6h8.9v-1.5H7.6v1.5z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - alignJustify - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="https://www.w3.org/2000/svg" - > - <path - d="M3 15h18v-2H3v2zm0 4h18v-2H3v2zm0-8h18V9H3v2zm0-6v2h18V5H3z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="https://www.w3.org/2000/svg" - > - <path - d="M3 15h18v-2H3v2zm0 4h18v-2H3v2zm0-8h18V9H3v2zm0-6v2h18V5H3z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="https://www.w3.org/2000/svg" - > - <path - d="M3 15h18v-2H3v2zm0 4h18v-2H3v2zm0-8h18V9H3v2zm0-6v2h18V5H3z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - alignLeft - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 19.8h8.9v-1.5H4v1.5zm8.9-15.6H4v1.5h8.9V4.2zm-8.9 7v1.5h16v-1.5H4z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 19.8h8.9v-1.5H4v1.5zm8.9-15.6H4v1.5h8.9V4.2zm-8.9 7v1.5h16v-1.5H4z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 19.8h8.9v-1.5H4v1.5zm8.9-15.6H4v1.5h8.9V4.2zm-8.9 7v1.5h16v-1.5H4z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - alignRight - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M11.1 19.8H20v-1.5h-8.9v1.5zm0-15.6v1.5H20V4.2h-8.9zM4 12.8h16v-1.5H4v1.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M11.1 19.8H20v-1.5h-8.9v1.5zm0-15.6v1.5H20V4.2h-8.9zM4 12.8h16v-1.5H4v1.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M11.1 19.8H20v-1.5h-8.9v1.5zm0-15.6v1.5H20V4.2h-8.9zM4 12.8h16v-1.5H4v1.5z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - archive - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19 6.2h-5.9l-.6-1.1c-.3-.7-1-1.1-1.8-1.1H5c-1.1 0-2 .9-2 2v11.8c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V8.2c0-1.1-.9-2-2-2zm.5 11.6c0 .3-.2.5-.5.5H5c-.3 0-.5-.2-.5-.5V6c0-.3.2-.5.5-.5h5.8c.2 0 .4.1.4.3l1 2H19c.3 0 .5.2.5.5v9.5zM8 12.8h8v-1.5H8v1.5zm0 3h8v-1.5H8v1.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19 6.2h-5.9l-.6-1.1c-.3-.7-1-1.1-1.8-1.1H5c-1.1 0-2 .9-2 2v11.8c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V8.2c0-1.1-.9-2-2-2zm.5 11.6c0 .3-.2.5-.5.5H5c-.3 0-.5-.2-.5-.5V6c0-.3.2-.5.5-.5h5.8c.2 0 .4.1.4.3l1 2H19c.3 0 .5.2.5.5v9.5zM8 12.8h8v-1.5H8v1.5zm0 3h8v-1.5H8v1.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19 6.2h-5.9l-.6-1.1c-.3-.7-1-1.1-1.8-1.1H5c-1.1 0-2 .9-2 2v11.8c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V8.2c0-1.1-.9-2-2-2zm.5 11.6c0 .3-.2.5-.5.5H5c-.3 0-.5-.2-.5-.5V6c0-.3.2-.5.5-.5h5.8c.2 0 .4.1.4.3l1 2H19c.3 0 .5.2.5.5v9.5zM8 12.8h8v-1.5H8v1.5zm0 3h8v-1.5H8v1.5z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - arrowDown - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9 2h2v12l4-4 2 1-7 7-7-7 2-1 4 4V2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9 2h2v12l4-4 2 1-7 7-7-7 2-1 4 4V2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9 2h2v12l4-4 2 1-7 7-7-7 2-1 4 4V2z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - arrowLeft - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18 9v2H6l4 4-1 2-7-7 7-7 1 2-4 4h12z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18 9v2H6l4 4-1 2-7-7 7-7 1 2-4 4h12z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18 9v2H6l4 4-1 2-7-7 7-7 1 2-4 4h12z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - arrowRight - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M2 11V9h12l-4-4 1-2 7 7-7 7-1-2 4-4H2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M2 11V9h12l-4-4 1-2 7 7-7 7-1-2 4-4H2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M2 11V9h12l-4-4 1-2 7 7-7 7-1-2 4-4H2z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - arrowUp - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M11 18H9V6l-4 4-2-1 7-7 7 7-2 1-4-4v12z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M11 18H9V6l-4 4-2-1 7-7 7 7-2 1-4-4v12z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M11 18H9V6l-4 4-2-1 7-7 7 7-2 1-4-4v12z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - audio - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M17.7 4.3c-1.2 0-2.8 0-3.8 1-.6.6-.9 1.5-.9 2.6V14c-.6-.6-1.5-1-2.5-1C8.6 13 7 14.6 7 16.5S8.6 20 10.5 20c1.5 0 2.8-1 3.3-2.3.5-.8.7-1.8.7-2.5V7.9c0-.7.2-1.2.5-1.6.6-.6 1.8-.6 2.8-.6h.3V4.3h-.4z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M17.7 4.3c-1.2 0-2.8 0-3.8 1-.6.6-.9 1.5-.9 2.6V14c-.6-.6-1.5-1-2.5-1C8.6 13 7 14.6 7 16.5S8.6 20 10.5 20c1.5 0 2.8-1 3.3-2.3.5-.8.7-1.8.7-2.5V7.9c0-.7.2-1.2.5-1.6.6-.6 1.8-.6 2.8-.6h.3V4.3h-.4z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M17.7 4.3c-1.2 0-2.8 0-3.8 1-.6.6-.9 1.5-.9 2.6V14c-.6-.6-1.5-1-2.5-1C8.6 13 7 14.6 7 16.5S8.6 20 10.5 20c1.5 0 2.8-1 3.3-2.3.5-.8.7-1.8.7-2.5V7.9c0-.7.2-1.2.5-1.6.6-.6 1.8-.6 2.8-.6h.3V4.3h-.4z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - backup - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13.65 2.88c3.93 2.01 5.48 6.84 3.47 10.77s-6.83 5.48-10.77 3.47c-1.87-.96-3.2-2.56-3.86-4.4l1.64-1.03c.45 1.57 1.52 2.95 3.08 3.76 3.01 1.54 6.69.35 8.23-2.66 1.55-3.01.36-6.69-2.65-8.24C9.78 3.01 6.1 4.2 4.56 7.21l1.88.97-4.95 3.08-.39-5.82 1.78.91C4.9 2.4 9.75.89 13.65 2.88zm-4.36 7.83C9.11 10.53 9 10.28 9 10c0-.07.03-.12.04-.19h-.01L10 5l.97 4.81L14 13l-4.5-2.12.02-.02c-.08-.04-.16-.09-.23-.15z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13.65 2.88c3.93 2.01 5.48 6.84 3.47 10.77s-6.83 5.48-10.77 3.47c-1.87-.96-3.2-2.56-3.86-4.4l1.64-1.03c.45 1.57 1.52 2.95 3.08 3.76 3.01 1.54 6.69.35 8.23-2.66 1.55-3.01.36-6.69-2.65-8.24C9.78 3.01 6.1 4.2 4.56 7.21l1.88.97-4.95 3.08-.39-5.82 1.78.91C4.9 2.4 9.75.89 13.65 2.88zm-4.36 7.83C9.11 10.53 9 10.28 9 10c0-.07.03-.12.04-.19h-.01L10 5l.97 4.81L14 13l-4.5-2.12.02-.02c-.08-.04-.16-.09-.23-.15z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13.65 2.88c3.93 2.01 5.48 6.84 3.47 10.77s-6.83 5.48-10.77 3.47c-1.87-.96-3.2-2.56-3.86-4.4l1.64-1.03c.45 1.57 1.52 2.95 3.08 3.76 3.01 1.54 6.69.35 8.23-2.66 1.55-3.01.36-6.69-2.65-8.24C9.78 3.01 6.1 4.2 4.56 7.21l1.88.97-4.95 3.08-.39-5.82 1.78.91C4.9 2.4 9.75.89 13.65 2.88zm-4.36 7.83C9.11 10.53 9 10.28 9 10c0-.07.03-.12.04-.19h-.01L10 5l.97 4.81L14 13l-4.5-2.12.02-.02c-.08-.04-.16-.09-.23-.15z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - blockDefault - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19 8h-1V6h-5v2h-2V6H6v2H5c-1.1 0-2 .9-2 2v8c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2v-8c0-1.1-.9-2-2-2zm.5 10c0 .3-.2.5-.5.5H5c-.3 0-.5-.2-.5-.5v-8c0-.3.2-.5.5-.5h14c.3 0 .5.2.5.5v8z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19 8h-1V6h-5v2h-2V6H6v2H5c-1.1 0-2 .9-2 2v8c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2v-8c0-1.1-.9-2-2-2zm.5 10c0 .3-.2.5-.5.5H5c-.3 0-.5-.2-.5-.5v-8c0-.3.2-.5.5-.5h14c.3 0 .5.2.5.5v8z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19 8h-1V6h-5v2h-2V6H6v2H5c-1.1 0-2 .9-2 2v8c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2v-8c0-1.1-.9-2-2-2zm.5 10c0 .3-.2.5-.5.5H5c-.3 0-.5-.2-.5-.5v-8c0-.3.2-.5.5-.5h14c.3 0 .5.2.5.5v8z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - blockTable - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM5 4.5h14c.3 0 .5.2.5.5v3.5h-15V5c0-.3.2-.5.5-.5zm8 5.5h6.5v3.5H13V10zm-1.5 3.5h-7V10h7v3.5zm-7 5.5v-4h7v4.5H5c-.3 0-.5-.2-.5-.5zm14.5.5h-6V15h6.5v4c0 .3-.2.5-.5.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM5 4.5h14c.3 0 .5.2.5.5v3.5h-15V5c0-.3.2-.5.5-.5zm8 5.5h6.5v3.5H13V10zm-1.5 3.5h-7V10h7v3.5zm-7 5.5v-4h7v4.5H5c-.3 0-.5-.2-.5-.5zm14.5.5h-6V15h6.5v4c0 .3-.2.5-.5.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM5 4.5h14c.3 0 .5.2.5.5v3.5h-15V5c0-.3.2-.5.5-.5zm8 5.5h6.5v3.5H13V10zm-1.5 3.5h-7V10h7v3.5zm-7 5.5v-4h7v4.5H5c-.3 0-.5-.2-.5-.5zm14.5.5h-6V15h6.5v4c0 .3-.2.5-.5.5z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - brush - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18.33 3.57s.27-.8-.31-1.36c-.53-.52-1.22-.24-1.22-.24-.61.3-5.76 3.47-7.67 5.57-.86.96-2.06 3.79-1.09 4.82.92.98 3.96-.17 4.79-1 2.06-2.06 5.21-7.17 5.5-7.79zM1.4 17.65c2.37-1.56 1.46-3.41 3.23-4.64.93-.65 2.22-.62 3.08.29.63.67.8 2.57-.16 3.46-1.57 1.45-4 1.55-6.15.89z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18.33 3.57s.27-.8-.31-1.36c-.53-.52-1.22-.24-1.22-.24-.61.3-5.76 3.47-7.67 5.57-.86.96-2.06 3.79-1.09 4.82.92.98 3.96-.17 4.79-1 2.06-2.06 5.21-7.17 5.5-7.79zM1.4 17.65c2.37-1.56 1.46-3.41 3.23-4.64.93-.65 2.22-.62 3.08.29.63.67.8 2.57-.16 3.46-1.57 1.45-4 1.55-6.15.89z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18.33 3.57s.27-.8-.31-1.36c-.53-.52-1.22-.24-1.22-.24-.61.3-5.76 3.47-7.67 5.57-.86.96-2.06 3.79-1.09 4.82.92.98 3.96-.17 4.79-1 2.06-2.06 5.21-7.17 5.5-7.79zM1.4 17.65c2.37-1.56 1.46-3.41 3.23-4.64.93-.65 2.22-.62 3.08.29.63.67.8 2.57-.16 3.46-1.57 1.45-4 1.55-6.15.89z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - button - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19 7H5c-1.1 0-2 .9-2 2v7c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V9c0-1.1-.9-2-2-2zm.5 9c0 .3-.2.5-.5.5H5c-.3 0-.5-.2-.5-.5V9c0-.3.2-.5.5-.5h14c.3 0 .5.2.5.5v7zM8 13.5h8V12H8v1.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19 7H5c-1.1 0-2 .9-2 2v7c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V9c0-1.1-.9-2-2-2zm.5 9c0 .3-.2.5-.5.5H5c-.3 0-.5-.2-.5-.5V9c0-.3.2-.5.5-.5h14c.3 0 .5.2.5.5v7zM8 13.5h8V12H8v1.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19 7H5c-1.1 0-2 .9-2 2v7c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V9c0-1.1-.9-2-2-2zm.5 9c0 .3-.2.5-.5.5H5c-.3 0-.5-.2-.5-.5V9c0-.3.2-.5.5-.5h14c.3 0 .5.2.5.5v7zM8 13.5h8V12H8v1.5z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - calendar - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm.5 16c0 .3-.2.5-.5.5H5c-.3 0-.5-.2-.5-.5V7h15v12zM9 10H7v2h2v-2zm0 4H7v2h2v-2zm4-4h-2v2h2v-2zm4 0h-2v2h2v-2zm-4 4h-2v2h2v-2zm4 0h-2v2h2v-2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm.5 16c0 .3-.2.5-.5.5H5c-.3 0-.5-.2-.5-.5V7h15v12zM9 10H7v2h2v-2zm0 4H7v2h2v-2zm4-4h-2v2h2v-2zm4 0h-2v2h2v-2zm-4 4h-2v2h2v-2zm4 0h-2v2h2v-2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm.5 16c0 .3-.2.5-.5.5H5c-.3 0-.5-.2-.5-.5V7h15v12zM9 10H7v2h2v-2zm0 4H7v2h2v-2zm4-4h-2v2h2v-2zm4 0h-2v2h2v-2zm-4 4h-2v2h2v-2zm4 0h-2v2h2v-2z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - camera - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M6 5V3H3v2h3zm12 10V4H9L7 6H2v9h16zm-7-8c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M6 5V3H3v2h3zm12 10V4H9L7 6H2v9h16zm-7-8c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M6 5V3H3v2h3zm12 10V4H9L7 6H2v9h16zm-7-8c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - capturePhoto - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M12 9.2c-2.2 0-3.9 1.8-3.9 4s1.8 4 3.9 4 4-1.8 4-4-1.8-4-4-4zm0 6.5c-1.4 0-2.4-1.1-2.4-2.5s1.1-2.5 2.4-2.5 2.5 1.1 2.5 2.5-1.1 2.5-2.5 2.5zM20.2 8c-.1 0-.3 0-.5-.1l-2.5-.8c-.4-.1-.8-.4-1.1-.8l-1-1.5c-.4-.5-1-.9-1.7-.9h-2.9c-.6.1-1.2.4-1.6 1l-1 1.5c-.3.3-.6.6-1.1.7l-2.5.8c-.2.1-.4.1-.6.1-1 .2-1.7.9-1.7 1.9v8.3c0 1 .9 1.9 2 1.9h16c1.1 0 2-.8 2-1.9V9.9c0-1-.7-1.7-1.8-1.9zm.3 10.1c0 .2-.2.4-.5.4H4c-.3 0-.5-.2-.5-.4V9.9c0-.1.2-.3.5-.4.2 0 .5-.1.8-.2l2.5-.8c.7-.2 1.4-.6 1.8-1.3l1-1.5c.1-.1.2-.2.4-.2h2.9c.2 0 .3.1.4.2l1 1.5c.4.7 1.1 1.1 1.9 1.4l2.5.8c.3.1.6.1.8.2.3 0 .4.2.4.4v8.1z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M12 9.2c-2.2 0-3.9 1.8-3.9 4s1.8 4 3.9 4 4-1.8 4-4-1.8-4-4-4zm0 6.5c-1.4 0-2.4-1.1-2.4-2.5s1.1-2.5 2.4-2.5 2.5 1.1 2.5 2.5-1.1 2.5-2.5 2.5zM20.2 8c-.1 0-.3 0-.5-.1l-2.5-.8c-.4-.1-.8-.4-1.1-.8l-1-1.5c-.4-.5-1-.9-1.7-.9h-2.9c-.6.1-1.2.4-1.6 1l-1 1.5c-.3.3-.6.6-1.1.7l-2.5.8c-.2.1-.4.1-.6.1-1 .2-1.7.9-1.7 1.9v8.3c0 1 .9 1.9 2 1.9h16c1.1 0 2-.8 2-1.9V9.9c0-1-.7-1.7-1.8-1.9zm.3 10.1c0 .2-.2.4-.5.4H4c-.3 0-.5-.2-.5-.4V9.9c0-.1.2-.3.5-.4.2 0 .5-.1.8-.2l2.5-.8c.7-.2 1.4-.6 1.8-1.3l1-1.5c.1-.1.2-.2.4-.2h2.9c.2 0 .3.1.4.2l1 1.5c.4.7 1.1 1.1 1.9 1.4l2.5.8c.3.1.6.1.8.2.3 0 .4.2.4.4v8.1z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M12 9.2c-2.2 0-3.9 1.8-3.9 4s1.8 4 3.9 4 4-1.8 4-4-1.8-4-4-4zm0 6.5c-1.4 0-2.4-1.1-2.4-2.5s1.1-2.5 2.4-2.5 2.5 1.1 2.5 2.5-1.1 2.5-2.5 2.5zM20.2 8c-.1 0-.3 0-.5-.1l-2.5-.8c-.4-.1-.8-.4-1.1-.8l-1-1.5c-.4-.5-1-.9-1.7-.9h-2.9c-.6.1-1.2.4-1.6 1l-1 1.5c-.3.3-.6.6-1.1.7l-2.5.8c-.2.1-.4.1-.6.1-1 .2-1.7.9-1.7 1.9v8.3c0 1 .9 1.9 2 1.9h16c1.1 0 2-.8 2-1.9V9.9c0-1-.7-1.7-1.8-1.9zm.3 10.1c0 .2-.2.4-.5.4H4c-.3 0-.5-.2-.5-.4V9.9c0-.1.2-.3.5-.4.2 0 .5-.1.8-.2l2.5-.8c.7-.2 1.4-.6 1.8-1.3l1-1.5c.1-.1.2-.2.4-.2h2.9c.2 0 .3.1.4.2l1 1.5c.4.7 1.1 1.1 1.9 1.4l2.5.8c.3.1.6.1.8.2.3 0 .4.2.4.4v8.1z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - captureVideo - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M14 5H4c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm.5 12c0 .3-.2.5-.5.5H4c-.3 0-.5-.2-.5-.5V7c0-.3.2-.5.5-.5h10c.3 0 .5.2.5.5v10zm2.5-7v4l5 3V7l-5 3zm3.5 4.4l-2-1.2v-2.3l2-1.2v4.7z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M14 5H4c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm.5 12c0 .3-.2.5-.5.5H4c-.3 0-.5-.2-.5-.5V7c0-.3.2-.5.5-.5h10c.3 0 .5.2.5.5v10zm2.5-7v4l5 3V7l-5 3zm3.5 4.4l-2-1.2v-2.3l2-1.2v4.7z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M14 5H4c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm.5 12c0 .3-.2.5-.5.5H4c-.3 0-.5-.2-.5-.5V7c0-.3.2-.5.5-.5h10c.3 0 .5.2.5.5v10zm2.5-7v4l5 3V7l-5 3zm3.5 4.4l-2-1.2v-2.3l2-1.2v4.7z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - category - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm.5 16c0 .3-.2.5-.5.5H5c-.3 0-.5-.2-.5-.5V7h15v12zM9 10H7v2h2v-2zm0 4H7v2h2v-2zm4-4h-2v2h2v-2zm4 0h-2v2h2v-2zm-4 4h-2v2h2v-2zm4 0h-2v2h2v-2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm.5 16c0 .3-.2.5-.5.5H5c-.3 0-.5-.2-.5-.5V7h15v12zM9 10H7v2h2v-2zm0 4H7v2h2v-2zm4-4h-2v2h2v-2zm4 0h-2v2h2v-2zm-4 4h-2v2h2v-2zm4 0h-2v2h2v-2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm.5 16c0 .3-.2.5-.5.5H5c-.3 0-.5-.2-.5-.5V7h15v12zM9 10H7v2h2v-2zm0 4H7v2h2v-2zm4-4h-2v2h2v-2zm4 0h-2v2h2v-2zm-4 4h-2v2h2v-2zm4 0h-2v2h2v-2z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - chartLine - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18 3.5c0 .62-.38 1.16-.92 1.38v13.11H1.99l4.22-6.73c-.13-.23-.21-.48-.21-.76C6 9.67 6.67 9 7.5 9S9 9.67 9 10.5c0 .13-.02.25-.05.37l1.44.63c.27-.3.67-.5 1.11-.5.18 0 .35.04.51.09l3.58-6.41c-.36-.27-.59-.7-.59-1.18 0-.83.67-1.5 1.5-1.5.19 0 .36.04.53.1l.05-.09v.11c.54.22.92.76.92 1.38zm-1.92 13.49V5.85l-3.29 5.89c.13.23.21.48.21.76 0 .83-.67 1.5-1.5 1.5s-1.5-.67-1.5-1.5l.01-.07-1.63-.72c-.25.18-.55.29-.88.29-.18 0-.35-.04-.51-.1l-3.2 5.09h12.29z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18 3.5c0 .62-.38 1.16-.92 1.38v13.11H1.99l4.22-6.73c-.13-.23-.21-.48-.21-.76C6 9.67 6.67 9 7.5 9S9 9.67 9 10.5c0 .13-.02.25-.05.37l1.44.63c.27-.3.67-.5 1.11-.5.18 0 .35.04.51.09l3.58-6.41c-.36-.27-.59-.7-.59-1.18 0-.83.67-1.5 1.5-1.5.19 0 .36.04.53.1l.05-.09v.11c.54.22.92.76.92 1.38zm-1.92 13.49V5.85l-3.29 5.89c.13.23.21.48.21.76 0 .83-.67 1.5-1.5 1.5s-1.5-.67-1.5-1.5l.01-.07-1.63-.72c-.25.18-.55.29-.88.29-.18 0-.35-.04-.51-.1l-3.2 5.09h12.29z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18 3.5c0 .62-.38 1.16-.92 1.38v13.11H1.99l4.22-6.73c-.13-.23-.21-.48-.21-.76C6 9.67 6.67 9 7.5 9S9 9.67 9 10.5c0 .13-.02.25-.05.37l1.44.63c.27-.3.67-.5 1.11-.5.18 0 .35.04.51.09l3.58-6.41c-.36-.27-.59-.7-.59-1.18 0-.83.67-1.5 1.5-1.5.19 0 .36.04.53.1l.05-.09v.11c.54.22.92.76.92 1.38zm-1.92 13.49V5.85l-3.29 5.89c.13.23.21.48.21.76 0 .83-.67 1.5-1.5 1.5s-1.5-.67-1.5-1.5l.01-.07-1.63-.72c-.25.18-.55.29-.88.29-.18 0-.35-.04-.51-.1l-3.2 5.09h12.29z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - check - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9 18.6L3.5 13l1-1L9 16.4l9.5-9.9 1 1z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9 18.6L3.5 13l1-1L9 16.4l9.5-9.9 1 1z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9 18.6L3.5 13l1-1L9 16.4l9.5-9.9 1 1z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - chevronDown - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M17 9.4L12 14 7 9.4l-1 1.2 6 5.4 6-5.4z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M17 9.4L12 14 7 9.4l-1 1.2 6 5.4 6-5.4z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M17 9.4L12 14 7 9.4l-1 1.2 6 5.4 6-5.4z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - chevronLeft - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M14.6 7l-1.2-1L8 12l5.4 6 1.2-1-4.6-5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M14.6 7l-1.2-1L8 12l5.4 6 1.2-1-4.6-5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M14.6 7l-1.2-1L8 12l5.4 6 1.2-1-4.6-5z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - chevronRight - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M10.6 6L9.4 7l4.6 5-4.6 5 1.2 1 5.4-6z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M10.6 6L9.4 7l4.6 5-4.6 5 1.2 1 5.4-6z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M10.6 6L9.4 7l4.6 5-4.6 5 1.2 1 5.4-6z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - chevronUp - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M12 8l-6 5.4 1 1.2 5-4.6 5 4.6 1-1.2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M12 8l-6 5.4 1 1.2 5-4.6 5 4.6 1-1.2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M12 8l-6 5.4 1 1.2 5-4.6 5 4.6 1-1.2z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - classic - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M20 6H4c-1.1 0-2 .9-2 2v9c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm.5 11c0 .3-.2.5-.5.5H4c-.3 0-.5-.2-.5-.5V8c0-.3.2-.5.5-.5h16c.3 0 .5.2.5.5v9zM10 10H8v2h2v-2zm-5 2h2v-2H5v2zm8-2h-2v2h2v-2zm-5 6h8v-2H8v2zm6-4h2v-2h-2v2zm3 0h2v-2h-2v2zm0 4h2v-2h-2v2zM5 16h2v-2H5v2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M20 6H4c-1.1 0-2 .9-2 2v9c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm.5 11c0 .3-.2.5-.5.5H4c-.3 0-.5-.2-.5-.5V8c0-.3.2-.5.5-.5h16c.3 0 .5.2.5.5v9zM10 10H8v2h2v-2zm-5 2h2v-2H5v2zm8-2h-2v2h2v-2zm-5 6h8v-2H8v2zm6-4h2v-2h-2v2zm3 0h2v-2h-2v2zm0 4h2v-2h-2v2zM5 16h2v-2H5v2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M20 6H4c-1.1 0-2 .9-2 2v9c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm.5 11c0 .3-.2.5-.5.5H4c-.3 0-.5-.2-.5-.5V8c0-.3.2-.5.5-.5h16c.3 0 .5.2.5.5v9zM10 10H8v2h2v-2zm-5 2h2v-2H5v2zm8-2h-2v2h2v-2zm-5 6h8v-2H8v2zm6-4h2v-2h-2v2zm3 0h2v-2h-2v2zm0 4h2v-2h-2v2zM5 16h2v-2H5v2z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - closeCircleFilled - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M10 2c4.42 0 8 3.58 8 8s-3.58 8-8 8-8-3.58-8-8 3.58-8 8-8zm5 11l-3-3 3-3-2-2-3 3-3-3-2 2 3 3-3 3 2 2 3-3 3 3z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M10 2c4.42 0 8 3.58 8 8s-3.58 8-8 8-8-3.58-8-8 3.58-8 8-8zm5 11l-3-3 3-3-2-2-3 3-3-3-2 2 3 3-3 3 2 2 3-3 3 3z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M10 2c4.42 0 8 3.58 8 8s-3.58 8-8 8-8-3.58-8-8 3.58-8 8-8zm5 11l-3-3 3-3-2-2-3 3-3-3-2 2 3 3-3 3 2 2 3-3 3 3z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - close - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13 11.8l6.1-6.3-1-1-6.1 6.2-6.1-6.2-1 1 6.1 6.3-6.5 6.7 1 1 6.5-6.6 6.5 6.6 1-1z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13 11.8l6.1-6.3-1-1-6.1 6.2-6.1-6.2-1 1 6.1 6.3-6.5 6.7 1 1 6.5-6.6 6.5 6.6 1-1z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13 11.8l6.1-6.3-1-1-6.1 6.2-6.1-6.2-1 1 6.1 6.3-6.5 6.7 1 1 6.5-6.6 6.5 6.6 1-1z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - cloudUpload - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M14.8 9c.1-.3.2-.6.2-1 0-2.2-1.8-4-4-4-1.5 0-2.9.9-3.5 2.2-.3-.1-.7-.2-1-.2C5.1 6 4 7.1 4 8.5c0 .2 0 .4.1.5-1.8.3-3.1 1.7-3.1 3.5C1 14.4 2.6 16 4.5 16H8v-3H5l4.5-4.5L14 13h-3v3h3.5c1.9 0 3.5-1.6 3.5-3.5 0-1.8-1.4-3.3-3.2-3.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M14.8 9c.1-.3.2-.6.2-1 0-2.2-1.8-4-4-4-1.5 0-2.9.9-3.5 2.2-.3-.1-.7-.2-1-.2C5.1 6 4 7.1 4 8.5c0 .2 0 .4.1.5-1.8.3-3.1 1.7-3.1 3.5C1 14.4 2.6 16 4.5 16H8v-3H5l4.5-4.5L14 13h-3v3h3.5c1.9 0 3.5-1.6 3.5-3.5 0-1.8-1.4-3.3-3.2-3.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M14.8 9c.1-.3.2-.6.2-1 0-2.2-1.8-4-4-4-1.5 0-2.9.9-3.5 2.2-.3-.1-.7-.2-1-.2C5.1 6 4 7.1 4 8.5c0 .2 0 .4.1.5-1.8.3-3.1 1.7-3.1 3.5C1 14.4 2.6 16 4.5 16H8v-3H5l4.5-4.5L14 13h-3v3h3.5c1.9 0 3.5-1.6 3.5-3.5 0-1.8-1.4-3.3-3.2-3.5z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - cloud - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M14.9 9c1.8.2 3.1 1.7 3.1 3.5 0 1.9-1.6 3.5-3.5 3.5h-10C2.6 16 1 14.4 1 12.5 1 10.7 2.3 9.3 4.1 9 4 8.9 4 8.7 4 8.5 4 7.1 5.1 6 6.5 6c.3 0 .7.1.9.2C8.1 4.9 9.4 4 11 4c2.2 0 4 1.8 4 4 0 .4-.1.7-.1 1z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M14.9 9c1.8.2 3.1 1.7 3.1 3.5 0 1.9-1.6 3.5-3.5 3.5h-10C2.6 16 1 14.4 1 12.5 1 10.7 2.3 9.3 4.1 9 4 8.9 4 8.7 4 8.5 4 7.1 5.1 6 6.5 6c.3 0 .7.1.9.2C8.1 4.9 9.4 4 11 4c2.2 0 4 1.8 4 4 0 .4-.1.7-.1 1z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M14.9 9c1.8.2 3.1 1.7 3.1 3.5 0 1.9-1.6 3.5-3.5 3.5h-10C2.6 16 1 14.4 1 12.5 1 10.7 2.3 9.3 4.1 9 4 8.9 4 8.7 4 8.5 4 7.1 5.1 6 6.5 6c.3 0 .7.1.9.2C8.1 4.9 9.4 4 11 4c2.2 0 4 1.8 4 4 0 .4-.1.7-.1 1z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - code - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M20.8 10.7l-4.3-4.3-1.1 1.1 4.3 4.3c.1.1.1.3 0 .4l-4.3 4.3 1.1 1.1 4.3-4.3c.7-.8.7-1.9 0-2.6zM4.2 11.8l4.3-4.3-1-1-4.3 4.3c-.7.7-.7 1.8 0 2.5l4.3 4.3 1.1-1.1-4.3-4.3c-.2-.1-.2-.3-.1-.4z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M20.8 10.7l-4.3-4.3-1.1 1.1 4.3 4.3c.1.1.1.3 0 .4l-4.3 4.3 1.1 1.1 4.3-4.3c.7-.8.7-1.9 0-2.6zM4.2 11.8l4.3-4.3-1-1-4.3 4.3c-.7.7-.7 1.8 0 2.5l4.3 4.3 1.1-1.1-4.3-4.3c-.2-.1-.2-.3-.1-.4z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M20.8 10.7l-4.3-4.3-1.1 1.1 4.3 4.3c.1.1.1.3 0 .4l-4.3 4.3 1.1 1.1 4.3-4.3c.7-.8.7-1.9 0-2.6zM4.2 11.8l4.3-4.3-1-1-4.3 4.3c-.7.7-.7 1.8 0 2.5l4.3 4.3 1.1-1.1-4.3-4.3c-.2-.1-.2-.3-.1-.4z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - cog - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18.4 12c0-.5 0-.9-.1-1.3l1.4-1.3-1.5-2.8-1.8.6c-.6-.6-1.4-1-2.2-1.3L13.8 4h-3l-.4 1.9c-.8.3-1.5.8-2.1 1.3l-1.8-.6L5 9.4l1.4 1.3c-.1.4-.1.9-.1 1.3s0 .9.1 1.3L5 14.6l1.5 2.8 1.8-.6c.6.6 1.4 1 2.2 1.3l.4 1.9h3l.4-1.9c.8-.3 1.5-.7 2.2-1.3l1.8.6 1.5-2.8-1.4-1.3c-.1-.4 0-.8 0-1.3zm-6.1 3.2c-1.7 0-3-1.4-3-3.2 0-1.8 1.4-3.2 3-3.2 1.7 0 3 1.4 3 3.2.1 1.8-1.3 3.2-3 3.2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18.4 12c0-.5 0-.9-.1-1.3l1.4-1.3-1.5-2.8-1.8.6c-.6-.6-1.4-1-2.2-1.3L13.8 4h-3l-.4 1.9c-.8.3-1.5.8-2.1 1.3l-1.8-.6L5 9.4l1.4 1.3c-.1.4-.1.9-.1 1.3s0 .9.1 1.3L5 14.6l1.5 2.8 1.8-.6c.6.6 1.4 1 2.2 1.3l.4 1.9h3l.4-1.9c.8-.3 1.5-.7 2.2-1.3l1.8.6 1.5-2.8-1.4-1.3c-.1-.4 0-.8 0-1.3zm-6.1 3.2c-1.7 0-3-1.4-3-3.2 0-1.8 1.4-3.2 3-3.2 1.7 0 3 1.4 3 3.2.1 1.8-1.3 3.2-3 3.2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18.4 12c0-.5 0-.9-.1-1.3l1.4-1.3-1.5-2.8-1.8.6c-.6-.6-1.4-1-2.2-1.3L13.8 4h-3l-.4 1.9c-.8.3-1.5.8-2.1 1.3l-1.8-.6L5 9.4l1.4 1.3c-.1.4-.1.9-.1 1.3s0 .9.1 1.3L5 14.6l1.5 2.8 1.8-.6c.6.6 1.4 1 2.2 1.3l.4 1.9h3l.4-1.9c.8-.3 1.5-.7 2.2-1.3l1.8.6 1.5-2.8-1.4-1.3c-.1-.4 0-.8 0-1.3zm-6.1 3.2c-1.7 0-3-1.4-3-3.2 0-1.8 1.4-3.2 3-3.2 1.7 0 3 1.4 3 3.2.1 1.8-1.3 3.2-3 3.2z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - column - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19 6H6c-1.1 0-2 .9-2 2v9c0 1.1.9 2 2 2h13c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zM6 17.5c-.3 0-.5-.2-.5-.5V8c0-.3.2-.5.5-.5h3v10H6zm13.5-.5c0 .3-.2.5-.5.5h-3v-10h3c.3 0 .5.2.5.5v9z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19 6H6c-1.1 0-2 .9-2 2v9c0 1.1.9 2 2 2h13c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zM6 17.5c-.3 0-.5-.2-.5-.5V8c0-.3.2-.5.5-.5h3v10H6zm13.5-.5c0 .3-.2.5-.5.5h-3v-10h3c.3 0 .5.2.5.5v9z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19 6H6c-1.1 0-2 .9-2 2v9c0 1.1.9 2 2 2h13c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zM6 17.5c-.3 0-.5-.2-.5-.5V8c0-.3.2-.5.5-.5h3v10H6zm13.5-.5c0 .3-.2.5-.5.5h-3v-10h3c.3 0 .5.2.5.5v9z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - columns - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19 6H6c-1.1 0-2 .9-2 2v9c0 1.1.9 2 2 2h13c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm-4.1 1.5v10H10v-10h4.9zM5.5 17V8c0-.3.2-.5.5-.5h2.5v10H6c-.3 0-.5-.2-.5-.5zm14 0c0 .3-.2.5-.5.5h-2.6v-10H19c.3 0 .5.2.5.5v9z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19 6H6c-1.1 0-2 .9-2 2v9c0 1.1.9 2 2 2h13c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm-4.1 1.5v10H10v-10h4.9zM5.5 17V8c0-.3.2-.5.5-.5h2.5v10H6c-.3 0-.5-.2-.5-.5zm14 0c0 .3-.2.5-.5.5h-2.6v-10H19c.3 0 .5.2.5.5v9z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19 6H6c-1.1 0-2 .9-2 2v9c0 1.1.9 2 2 2h13c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm-4.1 1.5v10H10v-10h4.9zM5.5 17V8c0-.3.2-.5.5-.5h2.5v10H6c-.3 0-.5-.2-.5-.5zm14 0c0 .3-.2.5-.5.5h-2.6v-10H19c.3 0 .5.2.5.5v9z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - comment - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18 4H6c-1.1 0-2 .9-2 2v12.9c0 .6.5 1.1 1.1 1.1.3 0 .5-.1.8-.3L8.5 17H18c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm.5 11c0 .3-.2.5-.5.5H7.9l-2.4 2.4V6c0-.3.2-.5.5-.5h12c.3 0 .5.2.5.5v9z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18 4H6c-1.1 0-2 .9-2 2v12.9c0 .6.5 1.1 1.1 1.1.3 0 .5-.1.8-.3L8.5 17H18c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm.5 11c0 .3-.2.5-.5.5H7.9l-2.4 2.4V6c0-.3.2-.5.5-.5h12c.3 0 .5.2.5.5v9z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18 4H6c-1.1 0-2 .9-2 2v12.9c0 .6.5 1.1 1.1 1.1.3 0 .5-.1.8-.3L8.5 17H18c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm.5 11c0 .3-.2.5-.5.5H7.9l-2.4 2.4V6c0-.3.2-.5.5-.5h12c.3 0 .5.2.5.5v9z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - controlsRepeat - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M5 7v3l-2 1.5V5h11V3l4 3.01L14 9V7H5zm10 6v-3l2-1.5V15H6v2l-4-3.01L6 11v2h9z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M5 7v3l-2 1.5V5h11V3l4 3.01L14 9V7H5zm10 6v-3l2-1.5V15H6v2l-4-3.01L6 11v2h9z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M5 7v3l-2 1.5V5h11V3l4 3.01L14 9V7H5zm10 6v-3l2-1.5V15H6v2l-4-3.01L6 11v2h9z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - cover - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18.7 3H5.3C4 3 3 4 3 5.3v13.4C3 20 4 21 5.3 21h13.4c1.3 0 2.3-1 2.3-2.3V5.3C21 4 20 3 18.7 3zm.8 15.7c0 .4-.4.8-.8.8H5.3c-.4 0-.8-.4-.8-.8V5.3c0-.4.4-.8.8-.8h6.2v8.9l2.5-3.1 2.5 3.1V4.5h2.2c.4 0 .8.4.8.8v13.4z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18.7 3H5.3C4 3 3 4 3 5.3v13.4C3 20 4 21 5.3 21h13.4c1.3 0 2.3-1 2.3-2.3V5.3C21 4 20 3 18.7 3zm.8 15.7c0 .4-.4.8-.8.8H5.3c-.4 0-.8-.4-.8-.8V5.3c0-.4.4-.8.8-.8h6.2v8.9l2.5-3.1 2.5 3.1V4.5h2.2c.4 0 .8.4.8.8v13.4z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18.7 3H5.3C4 3 3 4 3 5.3v13.4C3 20 4 21 5.3 21h13.4c1.3 0 2.3-1 2.3-2.3V5.3C21 4 20 3 18.7 3zm.8 15.7c0 .4-.4.8-.8.8H5.3c-.4 0-.8-.4-.8-.8V5.3c0-.4.4-.8.8-.8h6.2v8.9l2.5-3.1 2.5 3.1V4.5h2.2c.4 0 .8.4.8.8v13.4z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - external - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18.2 17c0 .7-.6 1.2-1.2 1.2H7c-.7 0-1.2-.6-1.2-1.2V7c0-.7.6-1.2 1.2-1.2h3.2V4.2H7C5.5 4.2 4.2 5.5 4.2 7v10c0 1.5 1.2 2.8 2.8 2.8h10c1.5 0 2.8-1.2 2.8-2.8v-3.6h-1.5V17zM14.9 3v1.5h3.7l-6.4 6.4 1.1 1.1 6.4-6.4v3.7h1.5V3h-6.3z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18.2 17c0 .7-.6 1.2-1.2 1.2H7c-.7 0-1.2-.6-1.2-1.2V7c0-.7.6-1.2 1.2-1.2h3.2V4.2H7C5.5 4.2 4.2 5.5 4.2 7v10c0 1.5 1.2 2.8 2.8 2.8h10c1.5 0 2.8-1.2 2.8-2.8v-3.6h-1.5V17zM14.9 3v1.5h3.7l-6.4 6.4 1.1 1.1 6.4-6.4v3.7h1.5V3h-6.3z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18.2 17c0 .7-.6 1.2-1.2 1.2H7c-.7 0-1.2-.6-1.2-1.2V7c0-.7.6-1.2 1.2-1.2h3.2V4.2H7C5.5 4.2 4.2 5.5 4.2 7v10c0 1.5 1.2 2.8 2.8 2.8h10c1.5 0 2.8-1.2 2.8-2.8v-3.6h-1.5V17zM14.9 3v1.5h3.7l-6.4 6.4 1.1 1.1 6.4-6.4v3.7h1.5V3h-6.3z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - file - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19 6.2h-5.9l-.6-1.1c-.3-.7-1-1.1-1.8-1.1H5c-1.1 0-2 .9-2 2v11.8c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V8.2c0-1.1-.9-2-2-2zm.5 11.6c0 .3-.2.5-.5.5H5c-.3 0-.5-.2-.5-.5V6c0-.3.2-.5.5-.5h5.8c.2 0 .4.1.4.3l1 2H19c.3 0 .5.2.5.5v9.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19 6.2h-5.9l-.6-1.1c-.3-.7-1-1.1-1.8-1.1H5c-1.1 0-2 .9-2 2v11.8c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V8.2c0-1.1-.9-2-2-2zm.5 11.6c0 .3-.2.5-.5.5H5c-.3 0-.5-.2-.5-.5V6c0-.3.2-.5.5-.5h5.8c.2 0 .4.1.4.3l1 2H19c.3 0 .5.2.5.5v9.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19 6.2h-5.9l-.6-1.1c-.3-.7-1-1.1-1.8-1.1H5c-1.1 0-2 .9-2 2v11.8c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V8.2c0-1.1-.9-2-2-2zm.5 11.6c0 .3-.2.5-.5.5H5c-.3 0-.5-.2-.5-.5V6c0-.3.2-.5.5-.5h5.8c.2 0 .4.1.4.3l1 2H19c.3 0 .5.2.5.5v9.5z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - formatBold - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M14.7 11.3c1-.6 1.5-1.6 1.5-3 0-2.3-1.3-3.4-4-3.4H7v14h5.8c1.4 0 2.5-.3 3.3-1 .8-.7 1.2-1.7 1.2-2.9.1-1.9-.8-3.1-2.6-3.7zm-5.1-4h2.3c.6 0 1.1.1 1.4.4.3.3.5.7.5 1.2s-.2 1-.5 1.2c-.3.3-.8.4-1.4.4H9.6V7.3zm4.6 9c-.4.3-1 .4-1.7.4H9.6v-3.9h2.9c.7 0 1.3.2 1.7.5.4.3.6.8.6 1.5s-.2 1.2-.6 1.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M14.7 11.3c1-.6 1.5-1.6 1.5-3 0-2.3-1.3-3.4-4-3.4H7v14h5.8c1.4 0 2.5-.3 3.3-1 .8-.7 1.2-1.7 1.2-2.9.1-1.9-.8-3.1-2.6-3.7zm-5.1-4h2.3c.6 0 1.1.1 1.4.4.3.3.5.7.5 1.2s-.2 1-.5 1.2c-.3.3-.8.4-1.4.4H9.6V7.3zm4.6 9c-.4.3-1 .4-1.7.4H9.6v-3.9h2.9c.7 0 1.3.2 1.7.5.4.3.6.8.6 1.5s-.2 1.2-.6 1.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M14.7 11.3c1-.6 1.5-1.6 1.5-3 0-2.3-1.3-3.4-4-3.4H7v14h5.8c1.4 0 2.5-.3 3.3-1 .8-.7 1.2-1.7 1.2-2.9.1-1.9-.8-3.1-2.6-3.7zm-5.1-4h2.3c.6 0 1.1.1 1.4.4.3.3.5.7.5 1.2s-.2 1-.5 1.2c-.3.3-.8.4-1.4.4H9.6V7.3zm4.6 9c-.4.3-1 .4-1.7.4H9.6v-3.9h2.9c.7 0 1.3.2 1.7.5.4.3.6.8.6 1.5s-.2 1.2-.6 1.5z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - formatIndent - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 7.2v1.5h16V7.2H4zm8 8.6h8v-1.5h-8v1.5zm-8-3.5l3 3-3 3 1 1 4-4-4-4-1 1z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 7.2v1.5h16V7.2H4zm8 8.6h8v-1.5h-8v1.5zm-8-3.5l3 3-3 3 1 1 4-4-4-4-1 1z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 7.2v1.5h16V7.2H4zm8 8.6h8v-1.5h-8v1.5zm-8-3.5l3 3-3 3 1 1 4-4-4-4-1 1z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - formatItalic - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M12.5 5L10 19h1.9l2.5-14z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M12.5 5L10 19h1.9l2.5-14z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M12.5 5L10 19h1.9l2.5-14z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - formatListBullets - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 7.2v1.5h16V7.2H4zm7.1 8.6H20v-1.5h-8.9v1.5zM6 13c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 7.2v1.5h16V7.2H4zm7.1 8.6H20v-1.5h-8.9v1.5zM6 13c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 7.2v1.5h16V7.2H4zm7.1 8.6H20v-1.5h-8.9v1.5zM6 13c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - formatListNumbered - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M11.1 15.8H20v-1.5h-8.9v1.5zM4 7.2v1.5h16V7.2H4zm.2 6.8l.8-.3V17h1v-4.7l-2.2.7.4 1z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M11.1 15.8H20v-1.5h-8.9v1.5zM4 7.2v1.5h16V7.2H4zm.2 6.8l.8-.3V17h1v-4.7l-2.2.7.4 1z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M11.1 15.8H20v-1.5h-8.9v1.5zM4 7.2v1.5h16V7.2H4zm.2 6.8l.8-.3V17h1v-4.7l-2.2.7.4 1z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - formatLtr - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M5.52 2h7.43c.55 0 1 .45 1 1s-.45 1-1 1h-1v13c0 .55-.45 1-1 1s-1-.45-1-1V5c0-.55-.45-1-1-1s-1 .45-1 1v12c0 .55-.45 1-1 1s-1-.45-1-1v-5.96h-.43C3.02 11.04 1 9.02 1 6.52S3.02 2 5.52 2zM14 14l5-4-5-4v8z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M5.52 2h7.43c.55 0 1 .45 1 1s-.45 1-1 1h-1v13c0 .55-.45 1-1 1s-1-.45-1-1V5c0-.55-.45-1-1-1s-1 .45-1 1v12c0 .55-.45 1-1 1s-1-.45-1-1v-5.96h-.43C3.02 11.04 1 9.02 1 6.52S3.02 2 5.52 2zM14 14l5-4-5-4v8z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M5.52 2h7.43c.55 0 1 .45 1 1s-.45 1-1 1h-1v13c0 .55-.45 1-1 1s-1-.45-1-1V5c0-.55-.45-1-1-1s-1 .45-1 1v12c0 .55-.45 1-1 1s-1-.45-1-1v-5.96h-.43C3.02 11.04 1 9.02 1 6.52S3.02 2 5.52 2zM14 14l5-4-5-4v8z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - formatOutdent - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 7.2v1.5h16V7.2H4zm8 8.6h8v-1.5h-8v1.5zm-4-4.6l-4 4 4 4 1-1-3-3 3-3-1-1z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 7.2v1.5h16V7.2H4zm8 8.6h8v-1.5h-8v1.5zm-4-4.6l-4 4 4 4 1-1-3-3 3-3-1-1z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 7.2v1.5h16V7.2H4zm8 8.6h8v-1.5h-8v1.5zm-4-4.6l-4 4 4 4 1-1-3-3 3-3-1-1z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - formatRtl - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M5.52 2h7.43c.55 0 1 .45 1 1s-.45 1-1 1h-1v13c0 .55-.45 1-1 1s-1-.45-1-1V5c0-.55-.45-1-1-1s-1 .45-1 1v12c0 .55-.45 1-1 1s-1-.45-1-1v-5.96h-.43C3.02 11.04 1 9.02 1 6.52S3.02 2 5.52 2zM19 6l-5 4 5 4V6zM5.52 2h7.43c.55 0 1 .45 1 1s-.45 1-1 1h-1v13c0 .55-.45 1-1 1s-1-.45-1-1V5c0-.55-.45-1-1-1s-1 .45-1 1v12c0 .55-.45 1-1 1s-1-.45-1-1v-5.96h-.43C3.02 11.04 1 9.02 1 6.52S3.02 2 5.52 2zM19 6l-5 4 5 4V6z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M5.52 2h7.43c.55 0 1 .45 1 1s-.45 1-1 1h-1v13c0 .55-.45 1-1 1s-1-.45-1-1V5c0-.55-.45-1-1-1s-1 .45-1 1v12c0 .55-.45 1-1 1s-1-.45-1-1v-5.96h-.43C3.02 11.04 1 9.02 1 6.52S3.02 2 5.52 2zM19 6l-5 4 5 4V6zM5.52 2h7.43c.55 0 1 .45 1 1s-.45 1-1 1h-1v13c0 .55-.45 1-1 1s-1-.45-1-1V5c0-.55-.45-1-1-1s-1 .45-1 1v12c0 .55-.45 1-1 1s-1-.45-1-1v-5.96h-.43C3.02 11.04 1 9.02 1 6.52S3.02 2 5.52 2zM19 6l-5 4 5 4V6z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M5.52 2h7.43c.55 0 1 .45 1 1s-.45 1-1 1h-1v13c0 .55-.45 1-1 1s-1-.45-1-1V5c0-.55-.45-1-1-1s-1 .45-1 1v12c0 .55-.45 1-1 1s-1-.45-1-1v-5.96h-.43C3.02 11.04 1 9.02 1 6.52S3.02 2 5.52 2zM19 6l-5 4 5 4V6zM5.52 2h7.43c.55 0 1 .45 1 1s-.45 1-1 1h-1v13c0 .55-.45 1-1 1s-1-.45-1-1V5c0-.55-.45-1-1-1s-1 .45-1 1v12c0 .55-.45 1-1 1s-1-.45-1-1v-5.96h-.43C3.02 11.04 1 9.02 1 6.52S3.02 2 5.52 2zM19 6l-5 4 5 4V6z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - formatStrikethrough - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9.1 9v-.5c0-.6.2-1.1.7-1.4.5-.3 1.2-.5 2-.5.7 0 1.4.1 2.1.3.7.2 1.4.5 2.1.9l.2-1.9c-.6-.3-1.2-.5-1.9-.7-.8-.1-1.6-.2-2.4-.2-1.5 0-2.7.3-3.6 1-.8.7-1.2 1.5-1.2 2.6V9h2zM20 12H4v1h8.3c.3.1.6.2.8.3.5.2.9.5 1.1.8.3.3.4.7.4 1.2 0 .7-.2 1.1-.8 1.5-.5.3-1.2.5-2.1.5-.8 0-1.6-.1-2.4-.3-.8-.2-1.5-.5-2.2-.8L7 18.1c.5.2 1.2.4 2 .6.8.2 1.6.3 2.4.3 1.7 0 3-.3 3.9-1 .9-.7 1.3-1.6 1.3-2.8 0-.9-.2-1.7-.7-2.2H20v-1z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9.1 9v-.5c0-.6.2-1.1.7-1.4.5-.3 1.2-.5 2-.5.7 0 1.4.1 2.1.3.7.2 1.4.5 2.1.9l.2-1.9c-.6-.3-1.2-.5-1.9-.7-.8-.1-1.6-.2-2.4-.2-1.5 0-2.7.3-3.6 1-.8.7-1.2 1.5-1.2 2.6V9h2zM20 12H4v1h8.3c.3.1.6.2.8.3.5.2.9.5 1.1.8.3.3.4.7.4 1.2 0 .7-.2 1.1-.8 1.5-.5.3-1.2.5-2.1.5-.8 0-1.6-.1-2.4-.3-.8-.2-1.5-.5-2.2-.8L7 18.1c.5.2 1.2.4 2 .6.8.2 1.6.3 2.4.3 1.7 0 3-.3 3.9-1 .9-.7 1.3-1.6 1.3-2.8 0-.9-.2-1.7-.7-2.2H20v-1z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9.1 9v-.5c0-.6.2-1.1.7-1.4.5-.3 1.2-.5 2-.5.7 0 1.4.1 2.1.3.7.2 1.4.5 2.1.9l.2-1.9c-.6-.3-1.2-.5-1.9-.7-.8-.1-1.6-.2-2.4-.2-1.5 0-2.7.3-3.6 1-.8.7-1.2 1.5-1.2 2.6V9h2zM20 12H4v1h8.3c.3.1.6.2.8.3.5.2.9.5 1.1.8.3.3.4.7.4 1.2 0 .7-.2 1.1-.8 1.5-.5.3-1.2.5-2.1.5-.8 0-1.6-.1-2.4-.3-.8-.2-1.5-.5-2.2-.8L7 18.1c.5.2 1.2.4 2 .6.8.2 1.6.3 2.4.3 1.7 0 3-.3 3.9-1 .9-.7 1.3-1.6 1.3-2.8 0-.9-.2-1.7-.7-2.2H20v-1z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - gallery - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M20.2 8v11c0 .7-.6 1.2-1.2 1.2H6v1.5h13c1.5 0 2.7-1.2 2.7-2.8V8h-1.5zM18 16.4V4.6c0-.9-.7-1.6-1.6-1.6H4.6C3.7 3 3 3.7 3 4.6v11.8c0 .9.7 1.6 1.6 1.6h11.8c.9 0 1.6-.7 1.6-1.6zM4.5 4.6c0-.1.1-.1.1-.1h11.8c.1 0 .1.1.1.1V12l-2.3-1.7c-.3-.2-.6-.2-.9 0l-2.9 2.1L8 11.3c-.2-.1-.5-.1-.7 0l-2.9 1.5V4.6zm0 11.8v-1.8l3.2-1.7 2.4 1.2c.2.1.5.1.8-.1l2.8-2 2.8 2v2.5c0 .1-.1.1-.1.1H4.6c0-.1-.1-.2-.1-.2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M20.2 8v11c0 .7-.6 1.2-1.2 1.2H6v1.5h13c1.5 0 2.7-1.2 2.7-2.8V8h-1.5zM18 16.4V4.6c0-.9-.7-1.6-1.6-1.6H4.6C3.7 3 3 3.7 3 4.6v11.8c0 .9.7 1.6 1.6 1.6h11.8c.9 0 1.6-.7 1.6-1.6zM4.5 4.6c0-.1.1-.1.1-.1h11.8c.1 0 .1.1.1.1V12l-2.3-1.7c-.3-.2-.6-.2-.9 0l-2.9 2.1L8 11.3c-.2-.1-.5-.1-.7 0l-2.9 1.5V4.6zm0 11.8v-1.8l3.2-1.7 2.4 1.2c.2.1.5.1.8-.1l2.8-2 2.8 2v2.5c0 .1-.1.1-.1.1H4.6c0-.1-.1-.2-.1-.2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M20.2 8v11c0 .7-.6 1.2-1.2 1.2H6v1.5h13c1.5 0 2.7-1.2 2.7-2.8V8h-1.5zM18 16.4V4.6c0-.9-.7-1.6-1.6-1.6H4.6C3.7 3 3 3.7 3 4.6v11.8c0 .9.7 1.6 1.6 1.6h11.8c.9 0 1.6-.7 1.6-1.6zM4.5 4.6c0-.1.1-.1.1-.1h11.8c.1 0 .1.1.1.1V12l-2.3-1.7c-.3-.2-.6-.2-.9 0l-2.9 2.1L8 11.3c-.2-.1-.5-.1-.7 0l-2.9 1.5V4.6zm0 11.8v-1.8l3.2-1.7 2.4 1.2c.2.1.5.1.8-.1l2.8-2 2.8 2v2.5c0 .1-.1.1-.1.1H4.6c0-.1-.1-.2-.1-.2z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - grid - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9 9V3H3v6h6zm8 0V3h-6v6h6zm-8 8v-6H3v6h6zm8 0v-6h-6v6h6z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9 9V3H3v6h6zm8 0V3h-6v6h6zm-8 8v-6H3v6h6zm8 0v-6h-6v6h6z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9 9V3H3v6h6zm8 0V3h-6v6h6zm-8 8v-6H3v6h6zm8 0v-6h-6v6h6z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - group - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18 4h-7c-1.1 0-2 .9-2 2v3H6c-1.1 0-2 .9-2 2v7c0 1.1.9 2 2 2h7c1.1 0 2-.9 2-2v-3h3c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm-4.5 14c0 .3-.2.5-.5.5H6c-.3 0-.5-.2-.5-.5v-7c0-.3.2-.5.5-.5h3V13c0 1.1.9 2 2 2h2.5v3zm0-4.5H11c-.3 0-.5-.2-.5-.5v-2.5H13c.3 0 .5.2.5.5v2.5zm5-.5c0 .3-.2.5-.5.5h-3V11c0-1.1-.9-2-2-2h-2.5V6c0-.3.2-.5.5-.5h7c.3 0 .5.2.5.5v7z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18 4h-7c-1.1 0-2 .9-2 2v3H6c-1.1 0-2 .9-2 2v7c0 1.1.9 2 2 2h7c1.1 0 2-.9 2-2v-3h3c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm-4.5 14c0 .3-.2.5-.5.5H6c-.3 0-.5-.2-.5-.5v-7c0-.3.2-.5.5-.5h3V13c0 1.1.9 2 2 2h2.5v3zm0-4.5H11c-.3 0-.5-.2-.5-.5v-2.5H13c.3 0 .5.2.5.5v2.5zm5-.5c0 .3-.2.5-.5.5h-3V11c0-1.1-.9-2-2-2h-2.5V6c0-.3.2-.5.5-.5h7c.3 0 .5.2.5.5v7z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18 4h-7c-1.1 0-2 .9-2 2v3H6c-1.1 0-2 .9-2 2v7c0 1.1.9 2 2 2h7c1.1 0 2-.9 2-2v-3h3c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm-4.5 14c0 .3-.2.5-.5.5H6c-.3 0-.5-.2-.5-.5v-7c0-.3.2-.5.5-.5h3V13c0 1.1.9 2 2 2h2.5v3zm0-4.5H11c-.3 0-.5-.2-.5-.5v-2.5H13c.3 0 .5.2.5.5v2.5zm5-.5c0 .3-.2.5-.5.5h-3V11c0-1.1-.9-2-2-2h-2.5V6c0-.3.2-.5.5-.5h7c.3 0 .5.2.5.5v7z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - heading - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M6.2 5.2v13.4l5.8-4.8 5.8 4.8V5.2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M6.2 5.2v13.4l5.8-4.8 5.8 4.8V5.2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M6.2 5.2v13.4l5.8-4.8 5.8 4.8V5.2z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - help - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M17 10c0-3.87-3.14-7-7-7-3.87 0-7 3.13-7 7s3.13 7 7 7c3.86 0 7-3.13 7-7zm-6.3 1.48H9.14v-.43c0-.38.08-.7.24-.98s.46-.57.88-.89c.41-.29.68-.53.81-.71.14-.18.2-.39.2-.62 0-.25-.09-.44-.28-.58-.19-.13-.45-.19-.79-.19-.58 0-1.25.19-2 .57l-.64-1.28c.87-.49 1.8-.74 2.77-.74.81 0 1.45.2 1.92.58.48.39.71.91.71 1.55 0 .43-.09.8-.29 1.11-.19.32-.57.67-1.11 1.06-.38.28-.61.49-.71.63-.1.15-.15.34-.15.57v.35zm-1.47 2.74c-.18-.17-.27-.42-.27-.73 0-.33.08-.58.26-.75s.43-.25.77-.25c.32 0 .57.09.75.26s.27.42.27.74c0 .3-.09.55-.27.72-.18.18-.43.27-.75.27-.33 0-.58-.09-.76-.26z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M17 10c0-3.87-3.14-7-7-7-3.87 0-7 3.13-7 7s3.13 7 7 7c3.86 0 7-3.13 7-7zm-6.3 1.48H9.14v-.43c0-.38.08-.7.24-.98s.46-.57.88-.89c.41-.29.68-.53.81-.71.14-.18.2-.39.2-.62 0-.25-.09-.44-.28-.58-.19-.13-.45-.19-.79-.19-.58 0-1.25.19-2 .57l-.64-1.28c.87-.49 1.8-.74 2.77-.74.81 0 1.45.2 1.92.58.48.39.71.91.71 1.55 0 .43-.09.8-.29 1.11-.19.32-.57.67-1.11 1.06-.38.28-.61.49-.71.63-.1.15-.15.34-.15.57v.35zm-1.47 2.74c-.18-.17-.27-.42-.27-.73 0-.33.08-.58.26-.75s.43-.25.77-.25c.32 0 .57.09.75.26s.27.42.27.74c0 .3-.09.55-.27.72-.18.18-.43.27-.75.27-.33 0-.58-.09-.76-.26z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M17 10c0-3.87-3.14-7-7-7-3.87 0-7 3.13-7 7s3.13 7 7 7c3.86 0 7-3.13 7-7zm-6.3 1.48H9.14v-.43c0-.38.08-.7.24-.98s.46-.57.88-.89c.41-.29.68-.53.81-.71.14-.18.2-.39.2-.62 0-.25-.09-.44-.28-.58-.19-.13-.45-.19-.79-.19-.58 0-1.25.19-2 .57l-.64-1.28c.87-.49 1.8-.74 2.77-.74.81 0 1.45.2 1.92.58.48.39.71.91.71 1.55 0 .43-.09.8-.29 1.11-.19.32-.57.67-1.11 1.06-.38.28-.61.49-.71.63-.1.15-.15.34-.15.57v.35zm-1.47 2.74c-.18-.17-.27-.42-.27-.73 0-.33.08-.58.26-.75s.43-.25.77-.25c.32 0 .57.09.75.26s.27.42.27.74c0 .3-.09.55-.27.72-.18.18-.43.27-.75.27-.33 0-.58-.09-.76-.26z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - html - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4.5,11h-2V9H1v6h1.5v-2.5h2V15H6V9H4.5V11z M7,10.5h1.5V15H10v-4.5h1.5V9H7V10.5z M14.5,10l-1-1H12v6h1.5v-3.9 l1,1l1-1V15H17V9h-1.5L14.5,10z M19.5,13.5V9H18v6h5v-1.5H19.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4.5,11h-2V9H1v6h1.5v-2.5h2V15H6V9H4.5V11z M7,10.5h1.5V15H10v-4.5h1.5V9H7V10.5z M14.5,10l-1-1H12v6h1.5v-3.9 l1,1l1-1V15H17V9h-1.5L14.5,10z M19.5,13.5V9H18v6h5v-1.5H19.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4.5,11h-2V9H1v6h1.5v-2.5h2V15H6V9H4.5V11z M7,10.5h1.5V15H10v-4.5h1.5V9H7V10.5z M14.5,10l-1-1H12v6h1.5v-3.9 l1,1l1-1V15H17V9h-1.5L14.5,10z M19.5,13.5V9H18v6h5v-1.5H19.5z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - image - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM5 4.5h14c.3 0 .5.2.5.5v8.4l-3-2.9c-.3-.3-.8-.3-1 0L11.9 14 9 12c-.3-.2-.6-.2-.8 0l-3.6 2.6V5c-.1-.3.1-.5.4-.5zm14 15H5c-.3 0-.5-.2-.5-.5v-2.4l4.1-3 3 1.9c.3.2.7.2.9-.1L16 12l3.5 3.4V19c0 .3-.2.5-.5.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM5 4.5h14c.3 0 .5.2.5.5v8.4l-3-2.9c-.3-.3-.8-.3-1 0L11.9 14 9 12c-.3-.2-.6-.2-.8 0l-3.6 2.6V5c-.1-.3.1-.5.4-.5zm14 15H5c-.3 0-.5-.2-.5-.5v-2.4l4.1-3 3 1.9c.3.2.7.2.9-.1L16 12l3.5 3.4V19c0 .3-.2.5-.5.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM5 4.5h14c.3 0 .5.2.5.5v8.4l-3-2.9c-.3-.3-.8-.3-1 0L11.9 14 9 12c-.3-.2-.6-.2-.8 0l-3.6 2.6V5c-.1-.3.1-.5.4-.5zm14 15H5c-.3 0-.5-.2-.5-.5v-2.4l4.1-3 3 1.9c.3.2.7.2.9-.1L16 12l3.5 3.4V19c0 .3-.2.5-.5.5z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - info - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M12 3.2c-4.8 0-8.8 3.9-8.8 8.8 0 4.8 3.9 8.8 8.8 8.8 4.8 0 8.8-3.9 8.8-8.8 0-4.8-4-8.8-8.8-8.8zm0 16c-4 0-7.2-3.3-7.2-7.2C4.8 8 8 4.8 12 4.8s7.2 3.3 7.2 7.2c0 4-3.2 7.2-7.2 7.2zM11 17h2v-5h-2v5zm0-7h2V8h-2v2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M12 3.2c-4.8 0-8.8 3.9-8.8 8.8 0 4.8 3.9 8.8 8.8 8.8 4.8 0 8.8-3.9 8.8-8.8 0-4.8-4-8.8-8.8-8.8zm0 16c-4 0-7.2-3.3-7.2-7.2C4.8 8 8 4.8 12 4.8s7.2 3.3 7.2 7.2c0 4-3.2 7.2-7.2 7.2zM11 17h2v-5h-2v5zm0-7h2V8h-2v2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M12 3.2c-4.8 0-8.8 3.9-8.8 8.8 0 4.8 3.9 8.8 8.8 8.8 4.8 0 8.8-3.9 8.8-8.8 0-4.8-4-8.8-8.8-8.8zm0 16c-4 0-7.2-3.3-7.2-7.2C4.8 8 8 4.8 12 4.8s7.2 3.3 7.2 7.2c0 4-3.2 7.2-7.2 7.2zM11 17h2v-5h-2v5zm0-7h2V8h-2v2z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - insertAfter - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9 12h2v-2h2V8h-2V6H9v2H7v2h2v2zm1 4c3.9 0 7-3.1 7-7s-3.1-7-7-7-7 3.1-7 7 3.1 7 7 7zm0-12c2.8 0 5 2.2 5 5s-2.2 5-5 5-5-2.2-5-5 2.2-5 5-5zM3 19h14v-2H3v2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9 12h2v-2h2V8h-2V6H9v2H7v2h2v2zm1 4c3.9 0 7-3.1 7-7s-3.1-7-7-7-7 3.1-7 7 3.1 7 7 7zm0-12c2.8 0 5 2.2 5 5s-2.2 5-5 5-5-2.2-5-5 2.2-5 5-5zM3 19h14v-2H3v2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9 12h2v-2h2V8h-2V6H9v2H7v2h2v2zm1 4c3.9 0 7-3.1 7-7s-3.1-7-7-7-7 3.1-7 7 3.1 7 7 7zm0-12c2.8 0 5 2.2 5 5s-2.2 5-5 5-5-2.2-5-5 2.2-5 5-5zM3 19h14v-2H3v2z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - insertBefore - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M11 8H9v2H7v2h2v2h2v-2h2v-2h-2V8zm-1-4c-3.9 0-7 3.1-7 7s3.1 7 7 7 7-3.1 7-7-3.1-7-7-7zm0 12c-2.8 0-5-2.2-5-5s2.2-5 5-5 5 2.2 5 5-2.2 5-5 5zM3 1v2h14V1H3z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M11 8H9v2H7v2h2v2h2v-2h2v-2h-2V8zm-1-4c-3.9 0-7 3.1-7 7s3.1 7 7 7 7-3.1 7-7-3.1-7-7-7zm0 12c-2.8 0-5-2.2-5-5s2.2-5 5-5 5 2.2 5 5-2.2 5-5 5zM3 1v2h14V1H3z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M11 8H9v2H7v2h2v2h2v-2h2v-2h-2V8zm-1-4c-3.9 0-7 3.1-7 7s3.1 7 7 7 7-3.1 7-7-3.1-7-7-7zm0 12c-2.8 0-5-2.2-5-5s2.2-5 5-5 5 2.2 5 5-2.2 5-5 5zM3 1v2h14V1H3z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - keyboardClose - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18,0 L2,0 C0.9,0 0.01,0.9 0.01,2 L0,12 C0,13.1 0.9,14 2,14 L18,14 C19.1,14 20,13.1 20,12 L20,2 C20,0.9 19.1,0 18,0 Z M18,12 L2,12 L2,2 L18,2 L18,12 Z M9,3 L11,3 L11,5 L9,5 L9,3 Z M9,6 L11,6 L11,8 L9,8 L9,6 Z M6,3 L8,3 L8,5 L6,5 L6,3 Z M6,6 L8,6 L8,8 L6,8 L6,6 Z M3,6 L5,6 L5,8 L3,8 L3,6 Z M3,3 L5,3 L5,5 L3,5 L3,3 Z M6,9 L14,9 L14,11 L6,11 L6,9 Z M12,6 L14,6 L14,8 L12,8 L12,6 Z M12,3 L14,3 L14,5 L12,5 L12,3 Z M15,6 L17,6 L17,8 L15,8 L15,6 Z M15,3 L17,3 L17,5 L15,5 L15,3 Z M10,20 L14,16 L6,16 L10,20 Z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18,0 L2,0 C0.9,0 0.01,0.9 0.01,2 L0,12 C0,13.1 0.9,14 2,14 L18,14 C19.1,14 20,13.1 20,12 L20,2 C20,0.9 19.1,0 18,0 Z M18,12 L2,12 L2,2 L18,2 L18,12 Z M9,3 L11,3 L11,5 L9,5 L9,3 Z M9,6 L11,6 L11,8 L9,8 L9,6 Z M6,3 L8,3 L8,5 L6,5 L6,3 Z M6,6 L8,6 L8,8 L6,8 L6,6 Z M3,6 L5,6 L5,8 L3,8 L3,6 Z M3,3 L5,3 L5,5 L3,5 L3,3 Z M6,9 L14,9 L14,11 L6,11 L6,9 Z M12,6 L14,6 L14,8 L12,8 L12,6 Z M12,3 L14,3 L14,5 L12,5 L12,3 Z M15,6 L17,6 L17,8 L15,8 L15,6 Z M15,3 L17,3 L17,5 L15,5 L15,3 Z M10,20 L14,16 L6,16 L10,20 Z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18,0 L2,0 C0.9,0 0.01,0.9 0.01,2 L0,12 C0,13.1 0.9,14 2,14 L18,14 C19.1,14 20,13.1 20,12 L20,2 C20,0.9 19.1,0 18,0 Z M18,12 L2,12 L2,2 L18,2 L18,12 Z M9,3 L11,3 L11,5 L9,5 L9,3 Z M9,6 L11,6 L11,8 L9,8 L9,6 Z M6,3 L8,3 L8,5 L6,5 L6,3 Z M6,6 L8,6 L8,8 L6,8 L6,6 Z M3,6 L5,6 L5,8 L3,8 L3,6 Z M3,3 L5,3 L5,5 L3,5 L3,3 Z M6,9 L14,9 L14,11 L6,11 L6,9 Z M12,6 L14,6 L14,8 L12,8 L12,6 Z M12,3 L14,3 L14,5 L12,5 L12,3 Z M15,6 L17,6 L17,8 L15,8 L15,6 Z M15,3 L17,3 L17,5 L15,5 L15,3 Z M10,20 L14,16 L6,16 L10,20 Z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - keyboardReturn - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M16 4h2v9H7v3l-5-4 5-4v3h9V4z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M16 4h2v9H7v3l-5-4 5-4v3h9V4z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M16 4h2v9H7v3l-5-4 5-4v3h9V4z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - layout - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M2 2h5v11H2V2zm6 0h5v5H8V2zm6 0h4v16h-4V2zM8 8h5v5H8V8zm-6 6h11v4H2v-4z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M2 2h5v11H2V2zm6 0h5v5H8V2zm6 0h4v16h-4V2zM8 8h5v5H8V8zm-6 6h11v4H2v-4z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M2 2h5v11H2V2zm6 0h5v5H8V2zm6 0h4v16h-4V2zM8 8h5v5H8V8zm-6 6h11v4H2v-4z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - link - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M15.6 7.2H14v1.5h1.6c2 0 3.7 1.7 3.7 3.7s-1.7 3.7-3.7 3.7H14v1.5h1.6c2.8 0 5.2-2.3 5.2-5.2 0-2.9-2.3-5.2-5.2-5.2zM4.7 12.4c0-2 1.7-3.7 3.7-3.7H10V7.2H8.4c-2.9 0-5.2 2.3-5.2 5.2 0 2.9 2.3 5.2 5.2 5.2H10v-1.5H8.4c-2 0-3.7-1.7-3.7-3.7zm4.6.9h5.3v-1.5H9.3v1.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M15.6 7.2H14v1.5h1.6c2 0 3.7 1.7 3.7 3.7s-1.7 3.7-3.7 3.7H14v1.5h1.6c2.8 0 5.2-2.3 5.2-5.2 0-2.9-2.3-5.2-5.2-5.2zM4.7 12.4c0-2 1.7-3.7 3.7-3.7H10V7.2H8.4c-2.9 0-5.2 2.3-5.2 5.2 0 2.9 2.3 5.2 5.2 5.2H10v-1.5H8.4c-2 0-3.7-1.7-3.7-3.7zm4.6.9h5.3v-1.5H9.3v1.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M15.6 7.2H14v1.5h1.6c2 0 3.7 1.7 3.7 3.7s-1.7 3.7-3.7 3.7H14v1.5h1.6c2.8 0 5.2-2.3 5.2-5.2 0-2.9-2.3-5.2-5.2-5.2zM4.7 12.4c0-2 1.7-3.7 3.7-3.7H10V7.2H8.4c-2.9 0-5.2 2.3-5.2 5.2 0 2.9 2.3 5.2 5.2 5.2H10v-1.5H8.4c-2 0-3.7-1.7-3.7-3.7zm4.6.9h5.3v-1.5H9.3v1.5z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - linkOff - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M15.6 7.3h-.7l1.6-3.5-.9-.4-3.9 8.5H9v1.5h2l-1.3 2.8H8.4c-2 0-3.7-1.7-3.7-3.7s1.7-3.7 3.7-3.7H10V7.3H8.4c-2.9 0-5.2 2.3-5.2 5.2 0 2.9 2.3 5.2 5.2 5.2H9l-1.4 3.2.9.4 5.7-12.5h1.4c2 0 3.7 1.7 3.7 3.7s-1.7 3.7-3.7 3.7H14v1.5h1.6c2.9 0 5.2-2.3 5.2-5.2 0-2.9-2.4-5.2-5.2-5.2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M15.6 7.3h-.7l1.6-3.5-.9-.4-3.9 8.5H9v1.5h2l-1.3 2.8H8.4c-2 0-3.7-1.7-3.7-3.7s1.7-3.7 3.7-3.7H10V7.3H8.4c-2.9 0-5.2 2.3-5.2 5.2 0 2.9 2.3 5.2 5.2 5.2H9l-1.4 3.2.9.4 5.7-12.5h1.4c2 0 3.7 1.7 3.7 3.7s-1.7 3.7-3.7 3.7H14v1.5h1.6c2.9 0 5.2-2.3 5.2-5.2 0-2.9-2.4-5.2-5.2-5.2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M15.6 7.3h-.7l1.6-3.5-.9-.4-3.9 8.5H9v1.5h2l-1.3 2.8H8.4c-2 0-3.7-1.7-3.7-3.7s1.7-3.7 3.7-3.7H10V7.3H8.4c-2.9 0-5.2 2.3-5.2 5.2 0 2.9 2.3 5.2 5.2 5.2H9l-1.4 3.2.9.4 5.7-12.5h1.4c2 0 3.7 1.7 3.7 3.7s-1.7 3.7-3.7 3.7H14v1.5h1.6c2.9 0 5.2-2.3 5.2-5.2 0-2.9-2.4-5.2-5.2-5.2z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - list - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 4v1.5h16V4H4zm8 8.5h8V11h-8v1.5zM4 20h16v-1.5H4V20zm4-8c0-1.1-.9-2-2-2s-2 .9-2 2 .9 2 2 2 2-.9 2-2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 4v1.5h16V4H4zm8 8.5h8V11h-8v1.5zM4 20h16v-1.5H4V20zm4-8c0-1.1-.9-2-2-2s-2 .9-2 2 .9 2 2 2 2-.9 2-2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 4v1.5h16V4H4zm8 8.5h8V11h-8v1.5zM4 20h16v-1.5H4V20zm4-8c0-1.1-.9-2-2-2s-2 .9-2 2 .9 2 2 2 2-.9 2-2z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - mapMarker - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="https://www.w3.org/2000/svg" - > - <path - d="M12.5 4C8.9 4 6 6.8 6 10.2c0 .8.3 1.8.9 3.1.5 1.1 1.2 2.3 2 3.6.7 1 3 3.8 3.2 3.9l.4.5.4-.5c.2-.2 2.6-2.9 3.2-3.9.8-1.2 1.5-2.5 2-3.6.6-1.3.9-2.3.9-3.1C19 6.8 16.1 4 12.5 4zm4.3 8.7c-.5 1-1.1 2.2-1.9 3.4-.5.7-1.7 2.2-2.4 3-.7-.8-1.9-2.3-2.4-3-.8-1.2-1.4-2.3-1.9-3.3-.6-1.4-.7-2.2-.7-2.5 0-2.6 2.2-4.7 5-4.7s5 2.1 5 4.7c0 .2-.1 1-.7 2.4zM12.5 9c-.8 0-1.5.7-1.5 1.5s.7 1.5 1.5 1.5 1.5-.7 1.5-1.5S13.3 9 12.5 9z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="https://www.w3.org/2000/svg" - > - <path - d="M12.5 4C8.9 4 6 6.8 6 10.2c0 .8.3 1.8.9 3.1.5 1.1 1.2 2.3 2 3.6.7 1 3 3.8 3.2 3.9l.4.5.4-.5c.2-.2 2.6-2.9 3.2-3.9.8-1.2 1.5-2.5 2-3.6.6-1.3.9-2.3.9-3.1C19 6.8 16.1 4 12.5 4zm4.3 8.7c-.5 1-1.1 2.2-1.9 3.4-.5.7-1.7 2.2-2.4 3-.7-.8-1.9-2.3-2.4-3-.8-1.2-1.4-2.3-1.9-3.3-.6-1.4-.7-2.2-.7-2.5 0-2.6 2.2-4.7 5-4.7s5 2.1 5 4.7c0 .2-.1 1-.7 2.4zM12.5 9c-.8 0-1.5.7-1.5 1.5s.7 1.5 1.5 1.5 1.5-.7 1.5-1.5S13.3 9 12.5 9z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="https://www.w3.org/2000/svg" - > - <path - d="M12.5 4C8.9 4 6 6.8 6 10.2c0 .8.3 1.8.9 3.1.5 1.1 1.2 2.3 2 3.6.7 1 3 3.8 3.2 3.9l.4.5.4-.5c.2-.2 2.6-2.9 3.2-3.9.8-1.2 1.5-2.5 2-3.6.6-1.3.9-2.3.9-3.1C19 6.8 16.1 4 12.5 4zm4.3 8.7c-.5 1-1.1 2.2-1.9 3.4-.5.7-1.7 2.2-2.4 3-.7-.8-1.9-2.3-2.4-3-.8-1.2-1.4-2.3-1.9-3.3-.6-1.4-.7-2.2-.7-2.5 0-2.6 2.2-4.7 5-4.7s5 2.1 5 4.7c0 .2-.1 1-.7 2.4zM12.5 9c-.8 0-1.5.7-1.5 1.5s.7 1.5 1.5 1.5 1.5-.7 1.5-1.5S13.3 9 12.5 9z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - media - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13 11V4c0-.55-.45-1-1-1h-1.67L9 1H5L3.67 3H2c-.55 0-1 .45-1 1v7c0 .55.45 1 1 1h10c.55 0 1-.45 1-1zM7 4.5c1.38 0 2.5 1.12 2.5 2.5S8.38 9.5 7 9.5 4.5 8.38 4.5 7 5.62 4.5 7 4.5zM14 6h5v10.5c0 1.38-1.12 2.5-2.5 2.5S14 17.88 14 16.5s1.12-2.5 2.5-2.5c.17 0 .34.02.5.05V9h-3V6zm-4 8.05V13h2v3.5c0 1.38-1.12 2.5-2.5 2.5S7 17.88 7 16.5 8.12 14 9.5 14c.17 0 .34.02.5.05z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13 11V4c0-.55-.45-1-1-1h-1.67L9 1H5L3.67 3H2c-.55 0-1 .45-1 1v7c0 .55.45 1 1 1h10c.55 0 1-.45 1-1zM7 4.5c1.38 0 2.5 1.12 2.5 2.5S8.38 9.5 7 9.5 4.5 8.38 4.5 7 5.62 4.5 7 4.5zM14 6h5v10.5c0 1.38-1.12 2.5-2.5 2.5S14 17.88 14 16.5s1.12-2.5 2.5-2.5c.17 0 .34.02.5.05V9h-3V6zm-4 8.05V13h2v3.5c0 1.38-1.12 2.5-2.5 2.5S7 17.88 7 16.5 8.12 14 9.5 14c.17 0 .34.02.5.05z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13 11V4c0-.55-.45-1-1-1h-1.67L9 1H5L3.67 3H2c-.55 0-1 .45-1 1v7c0 .55.45 1 1 1h10c.55 0 1-.45 1-1zM7 4.5c1.38 0 2.5 1.12 2.5 2.5S8.38 9.5 7 9.5 4.5 8.38 4.5 7 5.62 4.5 7 4.5zM14 6h5v10.5c0 1.38-1.12 2.5-2.5 2.5S14 17.88 14 16.5s1.12-2.5 2.5-2.5c.17 0 .34.02.5.05V9h-3V6zm-4 8.05V13h2v3.5c0 1.38-1.12 2.5-2.5 2.5S7 17.88 7 16.5 8.12 14 9.5 14c.17 0 .34.02.5.05z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - mediaAndText - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 17h7V6H4v11zm9-10v1.5h7V7h-7zm0 5.5h7V11h-7v1.5zm0 4h7V15h-7v1.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 17h7V6H4v11zm9-10v1.5h7V7h-7zm0 5.5h7V11h-7v1.5zm0 4h7V15h-7v1.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 17h7V6H4v11zm9-10v1.5h7V7h-7zm0 5.5h7V11h-7v1.5zm0 4h7V15h-7v1.5z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - menu - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M17 7V5H3v2h14zm0 4V9H3v2h14zm0 4v-2H3v2h14z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M17 7V5H3v2h14zm0 4V9H3v2h14zm0 4v-2H3v2h14z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M17 7V5H3v2h14zm0 4V9H3v2h14zm0 4v-2H3v2h14z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - minus - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 9h12v2H4V9z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 9h12v2H4V9z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 9h12v2H4V9z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - more - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 9v1.5h16V9H4zm12 5.5h4V13h-4v1.5zm-6 0h4V13h-4v1.5zm-6 0h4V13H4v1.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 9v1.5h16V9H4zm12 5.5h4V13h-4v1.5zm-6 0h4V13h-4v1.5zm-6 0h4V13H4v1.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 9v1.5h16V9H4zm12 5.5h4V13h-4v1.5zm-6 0h4V13h-4v1.5zm-6 0h4V13H4v1.5z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - moreHorizontal - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M11 13h2v-2h-2v2zm-6 0h2v-2H5v2zm12-2v2h2v-2h-2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M11 13h2v-2h-2v2zm-6 0h2v-2H5v2zm12-2v2h2v-2h-2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M11 13h2v-2h-2v2zm-6 0h2v-2H5v2zm12-2v2h2v-2h-2z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - moreVertical - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13 19h-2v-2h2v2zm0-6h-2v-2h2v2zm0-6h-2V5h2v2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13 19h-2v-2h2v2zm0-6h-2v-2h2v2zm0-6h-2V5h2v2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13 19h-2v-2h2v2zm0-6h-2v-2h2v2zm0-6h-2V5h2v2z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - navigation - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M12 4c-4.4 0-8 3.6-8 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zm0 14.5c-3.6 0-6.5-2.9-6.5-6.5S8.4 5.5 12 5.5s6.5 2.9 6.5 6.5-2.9 6.5-6.5 6.5zM9 16l4.5-3L15 8.4l-4.5 3L9 16z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M12 4c-4.4 0-8 3.6-8 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zm0 14.5c-3.6 0-6.5-2.9-6.5-6.5S8.4 5.5 12 5.5s6.5 2.9 6.5 6.5-2.9 6.5-6.5 6.5zM9 16l4.5-3L15 8.4l-4.5 3L9 16z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M12 4c-4.4 0-8 3.6-8 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zm0 14.5c-3.6 0-6.5-2.9-6.5-6.5S8.4 5.5 12 5.5s6.5 2.9 6.5 6.5-2.9 6.5-6.5 6.5zM9 16l4.5-3L15 8.4l-4.5 3L9 16z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - pageBreak - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M7.8 6c0-.7.6-1.2 1.2-1.2h6c.7 0 1.2.6 1.2 1.2v3h1.5V6c0-1.5-1.2-2.8-2.8-2.8H9C7.5 3.2 6.2 4.5 6.2 6v3h1.5V6zm8.4 11c0 .7-.6 1.2-1.2 1.2H9c-.7 0-1.2-.6-1.2-1.2v-3H6.2v3c0 1.5 1.2 2.8 2.8 2.8h6c1.5 0 2.8-1.2 2.8-2.8v-3h-1.5v3zM4 11v1h16v-1H4z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M7.8 6c0-.7.6-1.2 1.2-1.2h6c.7 0 1.2.6 1.2 1.2v3h1.5V6c0-1.5-1.2-2.8-2.8-2.8H9C7.5 3.2 6.2 4.5 6.2 6v3h1.5V6zm8.4 11c0 .7-.6 1.2-1.2 1.2H9c-.7 0-1.2-.6-1.2-1.2v-3H6.2v3c0 1.5 1.2 2.8 2.8 2.8h6c1.5 0 2.8-1.2 2.8-2.8v-3h-1.5v3zM4 11v1h16v-1H4z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M7.8 6c0-.7.6-1.2 1.2-1.2h6c.7 0 1.2.6 1.2 1.2v3h1.5V6c0-1.5-1.2-2.8-2.8-2.8H9C7.5 3.2 6.2 4.5 6.2 6v3h1.5V6zm8.4 11c0 .7-.6 1.2-1.2 1.2H9c-.7 0-1.2-.6-1.2-1.2v-3H6.2v3c0 1.5 1.2 2.8 2.8 2.8h6c1.5 0 2.8-1.2 2.8-2.8v-3h-1.5v3zM4 11v1h16v-1H4z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - page - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M6 15V2h10v13H6zm-1 1h8v2H3V5h2v11z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M6 15V2h10v13H6zm-1 1h8v2H3V5h2v11z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M6 15V2h10v13H6zm-1 1h8v2H3V5h2v11z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - paragraph - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18.3 4H9.9v-.1l-.9.2c-2.3.4-4 2.4-4 4.8s1.7 4.4 4 4.8l.7.1V20h1.5V5.5h2.9V20h1.5V5.5h2.7V4z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18.3 4H9.9v-.1l-.9.2c-2.3.4-4 2.4-4 4.8s1.7 4.4 4 4.8l.7.1V20h1.5V5.5h2.9V20h1.5V5.5h2.7V4z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18.3 4H9.9v-.1l-.9.2c-2.3.4-4 2.4-4 4.8s1.7 4.4 4 4.8l.7.1V20h1.5V5.5h2.9V20h1.5V5.5h2.7V4z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - positionCenter - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M5 15h14V9H5v6zm0 4.8h14v-1.5H5v1.5zM5 4.2v1.5h14V4.2H5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M5 15h14V9H5v6zm0 4.8h14v-1.5H5v1.5zM5 4.2v1.5h14V4.2H5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M5 15h14V9H5v6zm0 4.8h14v-1.5H5v1.5zM5 4.2v1.5h14V4.2H5z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - positionLeft - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 9v6h14V9H4zm8-4.8H4v1.5h8V4.2zM4 19.8h8v-1.5H4v1.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 9v6h14V9H4zm8-4.8H4v1.5h8V4.2zM4 19.8h8v-1.5H4v1.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 9v6h14V9H4zm8-4.8H4v1.5h8V4.2zM4 19.8h8v-1.5H4v1.5z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - positionRight - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M6 15h14V9H6v6zm6-10.8v1.5h8V4.2h-8zm0 15.6h8v-1.5h-8v1.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M6 15h14V9H6v6zm6-10.8v1.5h8V4.2h-8zm0 15.6h8v-1.5h-8v1.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M6 15h14V9H6v6zm6-10.8v1.5h8V4.2h-8zm0 15.6h8v-1.5h-8v1.5z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - pencil - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13.89 3.39l2.71 2.72c.46.46.42 1.24.03 1.64l-8.01 8.02-5.56 1.16 1.16-5.58s7.6-7.63 7.99-8.03c.39-.39 1.22-.39 1.68.07zm-2.73 2.79l-5.59 5.61 1.11 1.11 5.54-5.65zm-2.97 8.23l5.58-5.6-1.07-1.08-5.59 5.6zM13.89 3.39l2.71 2.72c.46.46.42 1.24.03 1.64l-8.01 8.02-5.56 1.16 1.16-5.58s7.6-7.63 7.99-8.03c.39-.39 1.22-.39 1.68.07zm-2.73 2.79l-5.59 5.61 1.11 1.11 5.54-5.65zm-2.97 8.23l5.58-5.6-1.07-1.08-5.59 5.6z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13.89 3.39l2.71 2.72c.46.46.42 1.24.03 1.64l-8.01 8.02-5.56 1.16 1.16-5.58s7.6-7.63 7.99-8.03c.39-.39 1.22-.39 1.68.07zm-2.73 2.79l-5.59 5.61 1.11 1.11 5.54-5.65zm-2.97 8.23l5.58-5.6-1.07-1.08-5.59 5.6zM13.89 3.39l2.71 2.72c.46.46.42 1.24.03 1.64l-8.01 8.02-5.56 1.16 1.16-5.58s7.6-7.63 7.99-8.03c.39-.39 1.22-.39 1.68.07zm-2.73 2.79l-5.59 5.61 1.11 1.11 5.54-5.65zm-2.97 8.23l5.58-5.6-1.07-1.08-5.59 5.6z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13.89 3.39l2.71 2.72c.46.46.42 1.24.03 1.64l-8.01 8.02-5.56 1.16 1.16-5.58s7.6-7.63 7.99-8.03c.39-.39 1.22-.39 1.68.07zm-2.73 2.79l-5.59 5.61 1.11 1.11 5.54-5.65zm-2.97 8.23l5.58-5.6-1.07-1.08-5.59 5.6zM13.89 3.39l2.71 2.72c.46.46.42 1.24.03 1.64l-8.01 8.02-5.56 1.16 1.16-5.58s7.6-7.63 7.99-8.03c.39-.39 1.22-.39 1.68.07zm-2.73 2.79l-5.59 5.61 1.11 1.11 5.54-5.65zm-2.97 8.23l5.58-5.6-1.07-1.08-5.59 5.6z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - pin - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M10.44 3.02l1.82-1.82 6.36 6.35-1.83 1.82c-1.05-.68-2.48-.57-3.41.36l-.75.75c-.92.93-1.04 2.35-.35 3.41l-1.83 1.82-2.41-2.41-2.8 2.79c-.42.42-3.38 2.71-3.8 2.29s1.86-3.39 2.28-3.81l2.79-2.79L4.1 9.36l1.83-1.82c1.05.69 2.48.57 3.4-.36l.75-.75c.93-.92 1.05-2.35.36-3.41z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M10.44 3.02l1.82-1.82 6.36 6.35-1.83 1.82c-1.05-.68-2.48-.57-3.41.36l-.75.75c-.92.93-1.04 2.35-.35 3.41l-1.83 1.82-2.41-2.41-2.8 2.79c-.42.42-3.38 2.71-3.8 2.29s1.86-3.39 2.28-3.81l2.79-2.79L4.1 9.36l1.83-1.82c1.05.69 2.48.57 3.4-.36l.75-.75c.93-.92 1.05-2.35.36-3.41z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M10.44 3.02l1.82-1.82 6.36 6.35-1.83 1.82c-1.05-.68-2.48-.57-3.41.36l-.75.75c-.92.93-1.04 2.35-.35 3.41l-1.83 1.82-2.41-2.41-2.8 2.79c-.42.42-3.38 2.71-3.8 2.29s1.86-3.39 2.28-3.81l2.79-2.79L4.1 9.36l1.83-1.82c1.05.69 2.48.57 3.4-.36l.75-.75c.93-.92 1.05-2.35.36-3.41z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - plugins - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13.11 4.36L9.87 7.6 8 5.73l3.24-3.24c.35-.34 1.05-.2 1.56.32.52.51.66 1.21.31 1.55zm-8 1.77l.91-1.12 9.01 9.01-1.19.84c-.71.71-2.63 1.16-3.82 1.16H6.14L4.9 17.26c-.59.59-1.54.59-2.12 0-.59-.58-.59-1.53 0-2.12l1.24-1.24v-3.88c0-1.13.4-3.19 1.09-3.89zm7.26 3.97l3.24-3.24c.34-.35 1.04-.21 1.55.31.52.51.66 1.21.31 1.55l-3.24 3.25z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13.11 4.36L9.87 7.6 8 5.73l3.24-3.24c.35-.34 1.05-.2 1.56.32.52.51.66 1.21.31 1.55zm-8 1.77l.91-1.12 9.01 9.01-1.19.84c-.71.71-2.63 1.16-3.82 1.16H6.14L4.9 17.26c-.59.59-1.54.59-2.12 0-.59-.58-.59-1.53 0-2.12l1.24-1.24v-3.88c0-1.13.4-3.19 1.09-3.89zm7.26 3.97l3.24-3.24c.34-.35 1.04-.21 1.55.31.52.51.66 1.21.31 1.55l-3.24 3.25z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13.11 4.36L9.87 7.6 8 5.73l3.24-3.24c.35-.34 1.05-.2 1.56.32.52.51.66 1.21.31 1.55zm-8 1.77l.91-1.12 9.01 9.01-1.19.84c-.71.71-2.63 1.16-3.82 1.16H6.14L4.9 17.26c-.59.59-1.54.59-2.12 0-.59-.58-.59-1.53 0-2.12l1.24-1.24v-3.88c0-1.13.4-3.19 1.09-3.89zm7.26 3.97l3.24-3.24c.34-.35 1.04-.21 1.55.31.52.51.66 1.21.31 1.55l-3.24 3.25z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - plusCircleFilled - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M2 12C2 6.44444 6.44444 2 12 2C17.5556 2 22 6.44444 22 12C22 17.5556 17.5556 22 12 22C6.44444 22 2 17.5556 2 12ZM13 11V7H11V11H7V13H11V17H13V13H17V11H13Z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M2 12C2 6.44444 6.44444 2 12 2C17.5556 2 22 6.44444 22 12C22 17.5556 17.5556 22 12 22C6.44444 22 2 17.5556 2 12ZM13 11V7H11V11H7V13H11V17H13V13H17V11H13Z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M2 12C2 6.44444 6.44444 2 12 2C17.5556 2 22 6.44444 22 12C22 17.5556 17.5556 22 12 22C6.44444 22 2 17.5556 2 12ZM13 11V7H11V11H7V13H11V17H13V13H17V11H13Z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - plusCircle - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M10 1c-5 0-9 4-9 9s4 9 9 9 9-4 9-9-4-9-9-9zm0 16c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7zm1-11H9v3H6v2h3v3h2v-3h3V9h-3V6zM10 1c-5 0-9 4-9 9s4 9 9 9 9-4 9-9-4-9-9-9zm0 16c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7zm1-11H9v3H6v2h3v3h2v-3h3V9h-3V6z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M10 1c-5 0-9 4-9 9s4 9 9 9 9-4 9-9-4-9-9-9zm0 16c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7zm1-11H9v3H6v2h3v3h2v-3h3V9h-3V6zM10 1c-5 0-9 4-9 9s4 9 9 9 9-4 9-9-4-9-9-9zm0 16c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7zm1-11H9v3H6v2h3v3h2v-3h3V9h-3V6z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M10 1c-5 0-9 4-9 9s4 9 9 9 9-4 9-9-4-9-9-9zm0 16c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7zm1-11H9v3H6v2h3v3h2v-3h3V9h-3V6zM10 1c-5 0-9 4-9 9s4 9 9 9 9-4 9-9-4-9-9-9zm0 16c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7zm1-11H9v3H6v2h3v3h2v-3h3V9h-3V6z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - plus - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18 11.2h-5.2V6h-1.6v5.2H6v1.6h5.2V18h1.6v-5.2H18z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18 11.2h-5.2V6h-1.6v5.2H6v1.6h5.2V18h1.6v-5.2H18z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18 11.2h-5.2V6h-1.6v5.2H6v1.6h5.2V18h1.6v-5.2H18z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - postList - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <rect - height="2" - width="6" - x="11" - y="7" - /> - <rect - height="2" - width="6" - x="11" - y="11" - /> - <rect - height="2" - width="6" - x="11" - y="15" - /> - <rect - height="2" - width="2" - x="7" - y="7" - /> - <rect - height="2" - width="2" - x="7" - y="11" - /> - <rect - height="2" - width="2" - x="7" - y="15" - /> - <path - d="M20.1,3H3.9C3.4,3,3,3.4,3,3.9v16.2C3,20.5,3.4,21,3.9,21h16.2c0.4,0,0.9-0.5,0.9-0.9V3.9C21,3.4,20.5,3,20.1,3z M19,19H5V5h14V19z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <rect - height="2" - width="6" - x="11" - y="7" - /> - <rect - height="2" - width="6" - x="11" - y="11" - /> - <rect - height="2" - width="6" - x="11" - y="15" - /> - <rect - height="2" - width="2" - x="7" - y="7" - /> - <rect - height="2" - width="2" - x="7" - y="11" - /> - <rect - height="2" - width="2" - x="7" - y="15" - /> - <path - d="M20.1,3H3.9C3.4,3,3,3.4,3,3.9v16.2C3,20.5,3.4,21,3.9,21h16.2c0.4,0,0.9-0.5,0.9-0.9V3.9C21,3.4,20.5,3,20.1,3z M19,19H5V5h14V19z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <rect - height="2" - width="6" - x="11" - y="7" - /> - <rect - height="2" - width="6" - x="11" - y="11" - /> - <rect - height="2" - width="6" - x="11" - y="15" - /> - <rect - height="2" - width="2" - x="7" - y="7" - /> - <rect - height="2" - width="2" - x="7" - y="11" - /> - <rect - height="2" - width="2" - x="7" - y="15" - /> - <path - d="M20.1,3H3.9C3.4,3,3,3.4,3,3.9v16.2C3,20.5,3.4,21,3.9,21h16.2c0.4,0,0.9-0.5,0.9-0.9V3.9C21,3.4,20.5,3,20.1,3z M19,19H5V5h14V19z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - preformatted - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18 4H6c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm.5 14c0 .3-.2.5-.5.5H6c-.3 0-.5-.2-.5-.5V6c0-.3.2-.5.5-.5h12c.3 0 .5.2.5.5v12zM7 16.5h6V15H7v1.5zm4-4h6V11h-6v1.5zM9 11H7v1.5h2V11zm6 5.5h2V15h-2v1.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18 4H6c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm.5 14c0 .3-.2.5-.5.5H6c-.3 0-.5-.2-.5-.5V6c0-.3.2-.5.5-.5h12c.3 0 .5.2.5.5v12zM7 16.5h6V15H7v1.5zm4-4h6V11h-6v1.5zM9 11H7v1.5h2V11zm6 5.5h2V15h-2v1.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18 4H6c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm.5 14c0 .3-.2.5-.5.5H6c-.3 0-.5-.2-.5-.5V6c0-.3.2-.5.5-.5h12c.3 0 .5.2.5.5v12zM7 16.5h6V15H7v1.5zm4-4h6V11h-6v1.5zM9 11H7v1.5h2V11zm6 5.5h2V15h-2v1.5z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - pullLeft - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 18h6V6H4v12zm9-10v1.5h7V8h-7zm0 7.5h7V14h-7v1.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 18h6V6H4v12zm9-10v1.5h7V8h-7zm0 7.5h7V14h-7v1.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 18h6V6H4v12zm9-10v1.5h7V8h-7zm0 7.5h7V14h-7v1.5z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - pullRight - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M14 6v12h6V6h-6zM4 9.5h7V8H4v1.5zm0 6h7V14H4v1.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M14 6v12h6V6h-6zM4 9.5h7V8H4v1.5zm0 6h7V14H4v1.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M14 6v12h6V6h-6zM4 9.5h7V8H4v1.5zm0 6h7V14H4v1.5z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - pullquote - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18 8H6c-1.1 0-2 .9-2 2v4c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2v-4c0-1.1-.9-2-2-2zm.5 6c0 .3-.2.5-.5.5H6c-.3 0-.5-.2-.5-.5v-4c0-.3.2-.5.5-.5h12c.3 0 .5.2.5.5v4zM4 4v1.5h16V4H4zm0 16h16v-1.5H4V20z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18 8H6c-1.1 0-2 .9-2 2v4c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2v-4c0-1.1-.9-2-2-2zm.5 6c0 .3-.2.5-.5.5H6c-.3 0-.5-.2-.5-.5v-4c0-.3.2-.5.5-.5h12c.3 0 .5.2.5.5v4zM4 4v1.5h16V4H4zm0 16h16v-1.5H4V20z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18 8H6c-1.1 0-2 .9-2 2v4c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2v-4c0-1.1-.9-2-2-2zm.5 6c0 .3-.2.5-.5.5H6c-.3 0-.5-.2-.5-.5v-4c0-.3.2-.5.5-.5h12c.3 0 .5.2.5.5v4zM4 4v1.5h16V4H4zm0 16h16v-1.5H4V20z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - quote - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13 6v6h5.2v4c0 .8-.2 1.4-.5 1.7-.6.6-1.6.6-2.5.5h-.3v1.5h.5c1 0 2.3-.1 3.3-1 .6-.6 1-1.6 1-2.8V6H13zm-9 6h5.2v4c0 .8-.2 1.4-.5 1.7-.6.6-1.6.6-2.5.5h-.3v1.5h.5c1 0 2.3-.1 3.3-1 .6-.6 1-1.6 1-2.8V6H4v6z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13 6v6h5.2v4c0 .8-.2 1.4-.5 1.7-.6.6-1.6.6-2.5.5h-.3v1.5h.5c1 0 2.3-.1 3.3-1 .6-.6 1-1.6 1-2.8V6H13zm-9 6h5.2v4c0 .8-.2 1.4-.5 1.7-.6.6-1.6.6-2.5.5h-.3v1.5h.5c1 0 2.3-.1 3.3-1 .6-.6 1-1.6 1-2.8V6H4v6z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13 6v6h5.2v4c0 .8-.2 1.4-.5 1.7-.6.6-1.6.6-2.5.5h-.3v1.5h.5c1 0 2.3-.1 3.3-1 .6-.6 1-1.6 1-2.8V6H13zm-9 6h5.2v4c0 .8-.2 1.4-.5 1.7-.6.6-1.6.6-2.5.5h-.3v1.5h.5c1 0 2.3-.1 3.3-1 .6-.6 1-1.6 1-2.8V6H4v6z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - redo - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M15.6 6.5l-1.1 1 2.9 3.3H8c-.9 0-1.7.3-2.3.9-1.4 1.5-1.4 4.2-1.4 5.6v.2h1.5v-.3c0-1.1 0-3.5 1-4.5.3-.3.7-.5 1.3-.5h9.2L14.5 15l1.1 1.1 4.6-4.6-4.6-5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M15.6 6.5l-1.1 1 2.9 3.3H8c-.9 0-1.7.3-2.3.9-1.4 1.5-1.4 4.2-1.4 5.6v.2h1.5v-.3c0-1.1 0-3.5 1-4.5.3-.3.7-.5 1.3-.5h9.2L14.5 15l1.1 1.1 4.6-4.6-4.6-5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M15.6 6.5l-1.1 1 2.9 3.3H8c-.9 0-1.7.3-2.3.9-1.4 1.5-1.4 4.2-1.4 5.6v.2h1.5v-.3c0-1.1 0-3.5 1-4.5.3-.3.7-.5 1.3-.5h9.2L14.5 15l1.1 1.1 4.6-4.6-4.6-5z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - replace - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M16 10h4c.6 0 1-.4 1-1V5c0-.6-.4-1-1-1h-4c-.6 0-1 .4-1 1v4c0 .6.4 1 1 1zm-8 4H4c-.6 0-1 .4-1 1v4c0 .6.4 1 1 1h4c.6 0 1-.4 1-1v-4c0-.6-.4-1-1-1zm10-2.6L14.5 15l1.1 1.1 1.7-1.7c-.1 1.1-.3 2.3-.9 2.9-.3.3-.7.5-1.3.5h-4.5v1.5H15c.9 0 1.7-.3 2.3-.9 1-1 1.3-2.7 1.4-4l1.8 1.8 1.1-1.1-3.6-3.7zM6.8 9.7c.1-1.1.3-2.3.9-2.9.4-.4.8-.6 1.3-.6h4.5V4.8H9c-.9 0-1.7.3-2.3.9-1 1-1.3 2.7-1.4 4L3.5 8l-1 1L6 12.6 9.5 9l-1-1-1.7 1.7z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M16 10h4c.6 0 1-.4 1-1V5c0-.6-.4-1-1-1h-4c-.6 0-1 .4-1 1v4c0 .6.4 1 1 1zm-8 4H4c-.6 0-1 .4-1 1v4c0 .6.4 1 1 1h4c.6 0 1-.4 1-1v-4c0-.6-.4-1-1-1zm10-2.6L14.5 15l1.1 1.1 1.7-1.7c-.1 1.1-.3 2.3-.9 2.9-.3.3-.7.5-1.3.5h-4.5v1.5H15c.9 0 1.7-.3 2.3-.9 1-1 1.3-2.7 1.4-4l1.8 1.8 1.1-1.1-3.6-3.7zM6.8 9.7c.1-1.1.3-2.3.9-2.9.4-.4.8-.6 1.3-.6h4.5V4.8H9c-.9 0-1.7.3-2.3.9-1 1-1.3 2.7-1.4 4L3.5 8l-1 1L6 12.6 9.5 9l-1-1-1.7 1.7z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M16 10h4c.6 0 1-.4 1-1V5c0-.6-.4-1-1-1h-4c-.6 0-1 .4-1 1v4c0 .6.4 1 1 1zm-8 4H4c-.6 0-1 .4-1 1v4c0 .6.4 1 1 1h4c.6 0 1-.4 1-1v-4c0-.6-.4-1-1-1zm10-2.6L14.5 15l1.1 1.1 1.7-1.7c-.1 1.1-.3 2.3-.9 2.9-.3.3-.7.5-1.3.5h-4.5v1.5H15c.9 0 1.7-.3 2.3-.9 1-1 1.3-2.7 1.4-4l1.8 1.8 1.1-1.1-3.6-3.7zM6.8 9.7c.1-1.1.3-2.3.9-2.9.4-.4.8-.6 1.3-.6h4.5V4.8H9c-.9 0-1.7.3-2.3.9-1 1-1.3 2.7-1.4 4L3.5 8l-1 1L6 12.6 9.5 9l-1-1-1.7 1.7z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - resizeCornerNE - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M12.5 4.2v1.6h4.7L5.8 17.2V12H4.2v7.8H12v-1.6H6.8L18.2 6.8v4.7h1.6V4.2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M12.5 4.2v1.6h4.7L5.8 17.2V12H4.2v7.8H12v-1.6H6.8L18.2 6.8v4.7h1.6V4.2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M12.5 4.2v1.6h4.7L5.8 17.2V12H4.2v7.8H12v-1.6H6.8L18.2 6.8v4.7h1.6V4.2z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - rss - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M5 10.2h-.8v1.5H5c1.9 0 3.8.8 5.1 2.1 1.4 1.4 2.1 3.2 2.1 5.1v.8h1.5V19c0-2.3-.9-4.5-2.6-6.2-1.6-1.6-3.8-2.6-6.1-2.6zm10.4-1.6C12.6 5.8 8.9 4.2 5 4.2h-.8v1.5H5c3.5 0 6.9 1.4 9.4 3.9s3.9 5.8 3.9 9.4v.8h1.5V19c0-3.9-1.6-7.6-4.4-10.4zM4 20h3v-3H4v3z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M5 10.2h-.8v1.5H5c1.9 0 3.8.8 5.1 2.1 1.4 1.4 2.1 3.2 2.1 5.1v.8h1.5V19c0-2.3-.9-4.5-2.6-6.2-1.6-1.6-3.8-2.6-6.1-2.6zm10.4-1.6C12.6 5.8 8.9 4.2 5 4.2h-.8v1.5H5c3.5 0 6.9 1.4 9.4 3.9s3.9 5.8 3.9 9.4v.8h1.5V19c0-3.9-1.6-7.6-4.4-10.4zM4 20h3v-3H4v3z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M5 10.2h-.8v1.5H5c1.9 0 3.8.8 5.1 2.1 1.4 1.4 2.1 3.2 2.1 5.1v.8h1.5V19c0-2.3-.9-4.5-2.6-6.2-1.6-1.6-3.8-2.6-6.1-2.6zm10.4-1.6C12.6 5.8 8.9 4.2 5 4.2h-.8v1.5H5c3.5 0 6.9 1.4 9.4 3.9s3.9 5.8 3.9 9.4v.8h1.5V19c0-3.9-1.6-7.6-4.4-10.4zM4 20h3v-3H4v3z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - search - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M12.14 4.18c1.87 1.87 2.11 4.75.72 6.89.12.1.22.21.36.31.2.16.47.36.81.59.34.24.56.39.66.47.42.31.73.57.94.78.32.32.6.65.84 1 .25.35.44.69.59 1.04.14.35.21.68.18 1-.02.32-.14.59-.36.81s-.49.34-.81.36c-.31.02-.65-.04-.99-.19-.35-.14-.7-.34-1.04-.59-.35-.24-.68-.52-1-.84-.21-.21-.47-.52-.77-.93-.1-.13-.25-.35-.47-.66-.22-.32-.4-.57-.56-.78-.16-.2-.29-.35-.44-.5-2.07 1.09-4.69.76-6.44-.98-2.14-2.15-2.14-5.64 0-7.78 2.15-2.15 5.63-2.15 7.78 0zm-1.41 6.36c1.36-1.37 1.36-3.58 0-4.95-1.37-1.37-3.59-1.37-4.95 0-1.37 1.37-1.37 3.58 0 4.95 1.36 1.37 3.58 1.37 4.95 0z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M12.14 4.18c1.87 1.87 2.11 4.75.72 6.89.12.1.22.21.36.31.2.16.47.36.81.59.34.24.56.39.66.47.42.31.73.57.94.78.32.32.6.65.84 1 .25.35.44.69.59 1.04.14.35.21.68.18 1-.02.32-.14.59-.36.81s-.49.34-.81.36c-.31.02-.65-.04-.99-.19-.35-.14-.7-.34-1.04-.59-.35-.24-.68-.52-1-.84-.21-.21-.47-.52-.77-.93-.1-.13-.25-.35-.47-.66-.22-.32-.4-.57-.56-.78-.16-.2-.29-.35-.44-.5-2.07 1.09-4.69.76-6.44-.98-2.14-2.15-2.14-5.64 0-7.78 2.15-2.15 5.63-2.15 7.78 0zm-1.41 6.36c1.36-1.37 1.36-3.58 0-4.95-1.37-1.37-3.59-1.37-4.95 0-1.37 1.37-1.37 3.58 0 4.95 1.36 1.37 3.58 1.37 4.95 0z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M12.14 4.18c1.87 1.87 2.11 4.75.72 6.89.12.1.22.21.36.31.2.16.47.36.81.59.34.24.56.39.66.47.42.31.73.57.94.78.32.32.6.65.84 1 .25.35.44.69.59 1.04.14.35.21.68.18 1-.02.32-.14.59-.36.81s-.49.34-.81.36c-.31.02-.65-.04-.99-.19-.35-.14-.7-.34-1.04-.59-.35-.24-.68-.52-1-.84-.21-.21-.47-.52-.77-.93-.1-.13-.25-.35-.47-.66-.22-.32-.4-.57-.56-.78-.16-.2-.29-.35-.44-.5-2.07 1.09-4.69.76-6.44-.98-2.14-2.15-2.14-5.64 0-7.78 2.15-2.15 5.63-2.15 7.78 0zm-1.41 6.36c1.36-1.37 1.36-3.58 0-4.95-1.37-1.37-3.59-1.37-4.95 0-1.37 1.37-1.37 3.58 0 4.95 1.36 1.37 3.58 1.37 4.95 0z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - separator - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M20.2 7v4H3.8V7H2.2v9h1.6v-3.5h16.4V16h1.6V7z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M20.2 7v4H3.8V7H2.2v9h1.6v-3.5h16.4V16h1.6V7z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M20.2 7v4H3.8V7H2.2v9h1.6v-3.5h16.4V16h1.6V7z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - shortcode - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M16 4.2v1.5h2.5v12.5H16v1.5h4V4.2h-4zM4.2 19.8h4v-1.5H5.8V5.8h2.5V4.2h-4l-.1 15.6zm5.1-3.1l1.4.6 4-10-1.4-.6-4 10z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M16 4.2v1.5h2.5v12.5H16v1.5h4V4.2h-4zM4.2 19.8h4v-1.5H5.8V5.8h2.5V4.2h-4l-.1 15.6zm5.1-3.1l1.4.6 4-10-1.4-.6-4 10z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M16 4.2v1.5h2.5v12.5H16v1.5h4V4.2h-4zM4.2 19.8h4v-1.5H5.8V5.8h2.5V4.2h-4l-.1 15.6zm5.1-3.1l1.4.6 4-10-1.4-.6-4 10z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - globe - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9 0C4.03 0 0 4.03 0 9s4.03 9 9 9 9-4.03 9-9-4.03-9-9-9zM1.11 9.68h2.51c.04.91.167 1.814.38 2.7H1.84c-.403-.85-.65-1.764-.73-2.7zm8.57-5.4V1.19c.964.366 1.756 1.08 2.22 2 .205.347.386.708.54 1.08l-2.76.01zm3.22 1.35c.232.883.37 1.788.41 2.7H9.68v-2.7h3.22zM8.32 1.19v3.09H5.56c.154-.372.335-.733.54-1.08.462-.924 1.255-1.64 2.22-2.01zm0 4.44v2.7H4.7c.04-.912.178-1.817.41-2.7h3.21zm-4.7 2.69H1.11c.08-.936.327-1.85.73-2.7H4c-.213.886-.34 1.79-.38 2.7zM4.7 9.68h3.62v2.7H5.11c-.232-.883-.37-1.788-.41-2.7zm3.63 4v3.09c-.964-.366-1.756-1.08-2.22-2-.205-.347-.386-.708-.54-1.08l2.76-.01zm1.35 3.09v-3.04h2.76c-.154.372-.335.733-.54 1.08-.464.92-1.256 1.634-2.22 2v-.04zm0-4.44v-2.7h3.62c-.04.912-.178 1.817-.41 2.7H9.68zm4.71-2.7h2.51c-.08.936-.327 1.85-.73 2.7H14c.21-.87.337-1.757.38-2.65l.01-.05zm0-1.35c-.046-.894-.176-1.78-.39-2.65h2.16c.403.85.65 1.764.73 2.7l-2.5-.05zm1-4H13.6c-.324-.91-.793-1.76-1.39-2.52 1.244.56 2.325 1.426 3.14 2.52h.04zm-9.6-2.52c-.597.76-1.066 1.61-1.39 2.52H2.65c.815-1.094 1.896-1.96 3.14-2.52zm-3.15 12H4.4c.324.91.793 1.76 1.39 2.52-1.248-.567-2.33-1.445-3.14-2.55l-.01.03zm9.56 2.52c.597-.76 1.066-1.61 1.39-2.52h1.76c-.82 1.08-1.9 1.933-3.14 2.48l-.01.04z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9 0C4.03 0 0 4.03 0 9s4.03 9 9 9 9-4.03 9-9-4.03-9-9-9zM1.11 9.68h2.51c.04.91.167 1.814.38 2.7H1.84c-.403-.85-.65-1.764-.73-2.7zm8.57-5.4V1.19c.964.366 1.756 1.08 2.22 2 .205.347.386.708.54 1.08l-2.76.01zm3.22 1.35c.232.883.37 1.788.41 2.7H9.68v-2.7h3.22zM8.32 1.19v3.09H5.56c.154-.372.335-.733.54-1.08.462-.924 1.255-1.64 2.22-2.01zm0 4.44v2.7H4.7c.04-.912.178-1.817.41-2.7h3.21zm-4.7 2.69H1.11c.08-.936.327-1.85.73-2.7H4c-.213.886-.34 1.79-.38 2.7zM4.7 9.68h3.62v2.7H5.11c-.232-.883-.37-1.788-.41-2.7zm3.63 4v3.09c-.964-.366-1.756-1.08-2.22-2-.205-.347-.386-.708-.54-1.08l2.76-.01zm1.35 3.09v-3.04h2.76c-.154.372-.335.733-.54 1.08-.464.92-1.256 1.634-2.22 2v-.04zm0-4.44v-2.7h3.62c-.04.912-.178 1.817-.41 2.7H9.68zm4.71-2.7h2.51c-.08.936-.327 1.85-.73 2.7H14c.21-.87.337-1.757.38-2.65l.01-.05zm0-1.35c-.046-.894-.176-1.78-.39-2.65h2.16c.403.85.65 1.764.73 2.7l-2.5-.05zm1-4H13.6c-.324-.91-.793-1.76-1.39-2.52 1.244.56 2.325 1.426 3.14 2.52h.04zm-9.6-2.52c-.597.76-1.066 1.61-1.39 2.52H2.65c.815-1.094 1.896-1.96 3.14-2.52zm-3.15 12H4.4c.324.91.793 1.76 1.39 2.52-1.248-.567-2.33-1.445-3.14-2.55l-.01.03zm9.56 2.52c.597-.76 1.066-1.61 1.39-2.52h1.76c-.82 1.08-1.9 1.933-3.14 2.48l-.01.04z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M9 0C4.03 0 0 4.03 0 9s4.03 9 9 9 9-4.03 9-9-4.03-9-9-9zM1.11 9.68h2.51c.04.91.167 1.814.38 2.7H1.84c-.403-.85-.65-1.764-.73-2.7zm8.57-5.4V1.19c.964.366 1.756 1.08 2.22 2 .205.347.386.708.54 1.08l-2.76.01zm3.22 1.35c.232.883.37 1.788.41 2.7H9.68v-2.7h3.22zM8.32 1.19v3.09H5.56c.154-.372.335-.733.54-1.08.462-.924 1.255-1.64 2.22-2.01zm0 4.44v2.7H4.7c.04-.912.178-1.817.41-2.7h3.21zm-4.7 2.69H1.11c.08-.936.327-1.85.73-2.7H4c-.213.886-.34 1.79-.38 2.7zM4.7 9.68h3.62v2.7H5.11c-.232-.883-.37-1.788-.41-2.7zm3.63 4v3.09c-.964-.366-1.756-1.08-2.22-2-.205-.347-.386-.708-.54-1.08l2.76-.01zm1.35 3.09v-3.04h2.76c-.154.372-.335.733-.54 1.08-.464.92-1.256 1.634-2.22 2v-.04zm0-4.44v-2.7h3.62c-.04.912-.178 1.817-.41 2.7H9.68zm4.71-2.7h2.51c-.08.936-.327 1.85-.73 2.7H14c.21-.87.337-1.757.38-2.65l.01-.05zm0-1.35c-.046-.894-.176-1.78-.39-2.65h2.16c.403.85.65 1.764.73 2.7l-2.5-.05zm1-4H13.6c-.324-.91-.793-1.76-1.39-2.52 1.244.56 2.325 1.426 3.14 2.52h.04zm-9.6-2.52c-.597.76-1.066 1.61-1.39 2.52H2.65c.815-1.094 1.896-1.96 3.14-2.52zm-3.15 12H4.4c.324.91.793 1.76 1.39 2.52-1.248-.567-2.33-1.445-3.14-2.55l-.01.03zm9.56 2.52c.597-.76 1.066-1.61 1.39-2.52h1.76c-.82 1.08-1.9 1.933-3.14 2.48l-.01.04z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - starEmpty - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M10 1L7 7l-6 .75 4.13 4.62L4 19l6-3 6 3-1.12-6.63L19 7.75 13 7zm0 2.24l2.34 4.69 4.65.58-3.18 3.56.87 5.15L10 14.88l-4.68 2.34.87-5.15-3.18-3.56 4.65-.58z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M10 1L7 7l-6 .75 4.13 4.62L4 19l6-3 6 3-1.12-6.63L19 7.75 13 7zm0 2.24l2.34 4.69 4.65.58-3.18 3.56.87 5.15L10 14.88l-4.68 2.34.87-5.15-3.18-3.56 4.65-.58z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M10 1L7 7l-6 .75 4.13 4.62L4 19l6-3 6 3-1.12-6.63L19 7.75 13 7zm0 2.24l2.34 4.69 4.65.58-3.18 3.56.87 5.15L10 14.88l-4.68 2.34.87-5.15-3.18-3.56 4.65-.58z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - starFilled - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M10 1l3 6 6 .75-4.12 4.62L16 19l-6-3-6 3 1.13-6.63L1 7.75 7 7z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M10 1l3 6 6 .75-4.12 4.62L16 19l-6-3-6 3 1.13-6.63L1 7.75 7 7z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M10 1l3 6 6 .75-4.12 4.62L16 19l-6-3-6 3 1.13-6.63L1 7.75 7 7z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - starHalf - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M10 1L7 7l-6 .75 4.13 4.62L4 19l6-3 6 3-1.12-6.63L19 7.75 13 7zm0 2.24l2.34 4.69 4.65.58-3.18 3.56.87 5.15L10 14.88V3.24z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M10 1L7 7l-6 .75 4.13 4.62L4 19l6-3 6 3-1.12-6.63L19 7.75 13 7zm0 2.24l2.34 4.69 4.65.58-3.18 3.56.87 5.15L10 14.88V3.24z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M10 1L7 7l-6 .75 4.13 4.62L4 19l6-3 6 3-1.12-6.63L19 7.75 13 7zm0 2.24l2.34 4.69 4.65.58-3.18 3.56.87 5.15L10 14.88V3.24z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - stretchFullWidth - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M5 4v11h14V4H5zm3 15.8h8v-1.5H8v1.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M5 4v11h14V4H5zm3 15.8h8v-1.5H8v1.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M5 4v11h14V4H5zm3 15.8h8v-1.5H8v1.5z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - stretchWide - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M5 9v6h14V9H5zm11-4.8H8v1.5h8V4.2zM8 19.8h8v-1.5H8v1.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M5 9v6h14V9H5zm11-4.8H8v1.5h8V4.2zM8 19.8h8v-1.5H8v1.5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M5 9v6h14V9H5zm11-4.8H8v1.5h8V4.2zM8 19.8h8v-1.5H8v1.5z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - tableColumnAfter - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M14.08 12.864V9.216h3.648V7.424H14.08V3.776h-1.728v3.648H8.64v1.792h3.712v3.648zM0 17.92V0h20.48v17.92H0zM6.4 1.28H1.28v3.84H6.4V1.28zm0 5.12H1.28v3.84H6.4V6.4zm0 5.12H1.28v3.84H6.4v-3.84zM19.2 1.28H7.68v14.08H19.2V1.28z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M14.08 12.864V9.216h3.648V7.424H14.08V3.776h-1.728v3.648H8.64v1.792h3.712v3.648zM0 17.92V0h20.48v17.92H0zM6.4 1.28H1.28v3.84H6.4V1.28zm0 5.12H1.28v3.84H6.4V6.4zm0 5.12H1.28v3.84H6.4v-3.84zM19.2 1.28H7.68v14.08H19.2V1.28z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M14.08 12.864V9.216h3.648V7.424H14.08V3.776h-1.728v3.648H8.64v1.792h3.712v3.648zM0 17.92V0h20.48v17.92H0zM6.4 1.28H1.28v3.84H6.4V1.28zm0 5.12H1.28v3.84H6.4V6.4zm0 5.12H1.28v3.84H6.4v-3.84zM19.2 1.28H7.68v14.08H19.2V1.28z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - tableColumnBefore - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M6.4 3.776v3.648H2.752v1.792H6.4v3.648h1.728V9.216h3.712V7.424H8.128V3.776zM0 17.92V0h20.48v17.92H0zM12.8 1.28H1.28v14.08H12.8V1.28zm6.4 0h-5.12v3.84h5.12V1.28zm0 5.12h-5.12v3.84h5.12V6.4zm0 5.12h-5.12v3.84h5.12v-3.84z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M6.4 3.776v3.648H2.752v1.792H6.4v3.648h1.728V9.216h3.712V7.424H8.128V3.776zM0 17.92V0h20.48v17.92H0zM12.8 1.28H1.28v14.08H12.8V1.28zm6.4 0h-5.12v3.84h5.12V1.28zm0 5.12h-5.12v3.84h5.12V6.4zm0 5.12h-5.12v3.84h5.12v-3.84z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M6.4 3.776v3.648H2.752v1.792H6.4v3.648h1.728V9.216h3.712V7.424H8.128V3.776zM0 17.92V0h20.48v17.92H0zM12.8 1.28H1.28v14.08H12.8V1.28zm6.4 0h-5.12v3.84h5.12V1.28zm0 5.12h-5.12v3.84h5.12V6.4zm0 5.12h-5.12v3.84h5.12v-3.84z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - tableColumnDelete - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M6.4 9.98L7.68 8.7v-.256L6.4 7.164V9.98zm6.4-1.532l1.28-1.28V9.92L12.8 8.64v-.192zm7.68 9.472V0H0v17.92h20.48zm-1.28-2.56h-5.12v-1.024l-.256.256-1.024-1.024v1.792H7.68v-1.792l-1.024 1.024-.256-.256v1.024H1.28V1.28H6.4v2.368l.704-.704.576.576V1.216h5.12V3.52l.96-.96.32.32V1.216h5.12V15.36zm-5.76-2.112l-3.136-3.136-3.264 3.264-1.536-1.536 3.264-3.264L5.632 5.44l1.536-1.536 3.136 3.136 3.2-3.2 1.536 1.536-3.2 3.2 3.136 3.136-1.536 1.536z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M6.4 9.98L7.68 8.7v-.256L6.4 7.164V9.98zm6.4-1.532l1.28-1.28V9.92L12.8 8.64v-.192zm7.68 9.472V0H0v17.92h20.48zm-1.28-2.56h-5.12v-1.024l-.256.256-1.024-1.024v1.792H7.68v-1.792l-1.024 1.024-.256-.256v1.024H1.28V1.28H6.4v2.368l.704-.704.576.576V1.216h5.12V3.52l.96-.96.32.32V1.216h5.12V15.36zm-5.76-2.112l-3.136-3.136-3.264 3.264-1.536-1.536 3.264-3.264L5.632 5.44l1.536-1.536 3.136 3.136 3.2-3.2 1.536 1.536-3.2 3.2 3.136 3.136-1.536 1.536z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M6.4 9.98L7.68 8.7v-.256L6.4 7.164V9.98zm6.4-1.532l1.28-1.28V9.92L12.8 8.64v-.192zm7.68 9.472V0H0v17.92h20.48zm-1.28-2.56h-5.12v-1.024l-.256.256-1.024-1.024v1.792H7.68v-1.792l-1.024 1.024-.256-.256v1.024H1.28V1.28H6.4v2.368l.704-.704.576.576V1.216h5.12V3.52l.96-.96.32.32V1.216h5.12V15.36zm-5.76-2.112l-3.136-3.136-3.264 3.264-1.536-1.536 3.264-3.264L5.632 5.44l1.536-1.536 3.136 3.136 3.2-3.2 1.536 1.536-3.2 3.2 3.136 3.136-1.536 1.536z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - tableRowAfter - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13.824 10.176h-2.88v-2.88H9.536v2.88h-2.88v1.344h2.88v2.88h1.408v-2.88h2.88zM0 17.92V0h20.48v17.92H0zM6.4 1.28H1.28v3.84H6.4V1.28zm6.4 0H7.68v3.84h5.12V1.28zm6.4 0h-5.12v3.84h5.12V1.28zm0 5.056H1.28v9.024H19.2V6.336z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13.824 10.176h-2.88v-2.88H9.536v2.88h-2.88v1.344h2.88v2.88h1.408v-2.88h2.88zM0 17.92V0h20.48v17.92H0zM6.4 1.28H1.28v3.84H6.4V1.28zm6.4 0H7.68v3.84h5.12V1.28zm6.4 0h-5.12v3.84h5.12V1.28zm0 5.056H1.28v9.024H19.2V6.336z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13.824 10.176h-2.88v-2.88H9.536v2.88h-2.88v1.344h2.88v2.88h1.408v-2.88h2.88zM0 17.92V0h20.48v17.92H0zM6.4 1.28H1.28v3.84H6.4V1.28zm6.4 0H7.68v3.84h5.12V1.28zm6.4 0h-5.12v3.84h5.12V1.28zm0 5.056H1.28v9.024H19.2V6.336z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - tableRowBefore - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M6.656 6.464h2.88v2.88h1.408v-2.88h2.88V5.12h-2.88V2.24H9.536v2.88h-2.88zM0 17.92V0h20.48v17.92H0zm7.68-2.56h5.12v-3.84H7.68v3.84zm-6.4 0H6.4v-3.84H1.28v3.84zM19.2 1.28H1.28v9.024H19.2V1.28zm0 10.24h-5.12v3.84h5.12v-3.84zM6.656 6.464h2.88v2.88h1.408v-2.88h2.88V5.12h-2.88V2.24H9.536v2.88h-2.88zM0 17.92V0h20.48v17.92H0zm7.68-2.56h5.12v-3.84H7.68v3.84zm-6.4 0H6.4v-3.84H1.28v3.84zM19.2 1.28H1.28v9.024H19.2V1.28zm0 10.24h-5.12v3.84h5.12v-3.84z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M6.656 6.464h2.88v2.88h1.408v-2.88h2.88V5.12h-2.88V2.24H9.536v2.88h-2.88zM0 17.92V0h20.48v17.92H0zm7.68-2.56h5.12v-3.84H7.68v3.84zm-6.4 0H6.4v-3.84H1.28v3.84zM19.2 1.28H1.28v9.024H19.2V1.28zm0 10.24h-5.12v3.84h5.12v-3.84zM6.656 6.464h2.88v2.88h1.408v-2.88h2.88V5.12h-2.88V2.24H9.536v2.88h-2.88zM0 17.92V0h20.48v17.92H0zm7.68-2.56h5.12v-3.84H7.68v3.84zm-6.4 0H6.4v-3.84H1.28v3.84zM19.2 1.28H1.28v9.024H19.2V1.28zm0 10.24h-5.12v3.84h5.12v-3.84z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M6.656 6.464h2.88v2.88h1.408v-2.88h2.88V5.12h-2.88V2.24H9.536v2.88h-2.88zM0 17.92V0h20.48v17.92H0zm7.68-2.56h5.12v-3.84H7.68v3.84zm-6.4 0H6.4v-3.84H1.28v3.84zM19.2 1.28H1.28v9.024H19.2V1.28zm0 10.24h-5.12v3.84h5.12v-3.84zM6.656 6.464h2.88v2.88h1.408v-2.88h2.88V5.12h-2.88V2.24H9.536v2.88h-2.88zM0 17.92V0h20.48v17.92H0zm7.68-2.56h5.12v-3.84H7.68v3.84zm-6.4 0H6.4v-3.84H1.28v3.84zM19.2 1.28H1.28v9.024H19.2V1.28zm0 10.24h-5.12v3.84h5.12v-3.84z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - tableRowDelete - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M17.728 11.456L14.592 8.32l3.2-3.2-1.536-1.536-3.2 3.2L9.92 3.648 8.384 5.12l3.2 3.2-3.264 3.264 1.536 1.536 3.264-3.264 3.136 3.136 1.472-1.536zM0 17.92V0h20.48v17.92H0zm19.2-6.4h-.448l-1.28-1.28H19.2V6.4h-1.792l1.28-1.28h.512V1.28H1.28v3.84h6.208l1.28 1.28H1.28v3.84h7.424l-1.28 1.28H1.28v3.84H19.2v-3.84z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M17.728 11.456L14.592 8.32l3.2-3.2-1.536-1.536-3.2 3.2L9.92 3.648 8.384 5.12l3.2 3.2-3.264 3.264 1.536 1.536 3.264-3.264 3.136 3.136 1.472-1.536zM0 17.92V0h20.48v17.92H0zm19.2-6.4h-.448l-1.28-1.28H19.2V6.4h-1.792l1.28-1.28h.512V1.28H1.28v3.84h6.208l1.28 1.28H1.28v3.84h7.424l-1.28 1.28H1.28v3.84H19.2v-3.84z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M17.728 11.456L14.592 8.32l3.2-3.2-1.536-1.536-3.2 3.2L9.92 3.648 8.384 5.12l3.2 3.2-3.264 3.264 1.536 1.536 3.264-3.264 3.136 3.136 1.472-1.536zM0 17.92V0h20.48v17.92H0zm19.2-6.4h-.448l-1.28-1.28H19.2V6.4h-1.792l1.28-1.28h.512V1.28H1.28v3.84h6.208l1.28 1.28H1.28v3.84h7.424l-1.28 1.28H1.28v3.84H19.2v-3.84z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - table - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 6v11.5h16V6H4zm1.5 1.5h6V11h-6V7.5zm0 8.5v-3.5h6V16h-6zm13 0H13v-3.5h5.5V16zM13 11V7.5h5.5V11H13z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 6v11.5h16V6H4zm1.5 1.5h6V11h-6V7.5zm0 8.5v-3.5h6V16h-6zm13 0H13v-3.5h5.5V16zM13 11V7.5h5.5V11H13z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M4 6v11.5h16V6H4zm1.5 1.5h6V11h-6V7.5zm0 8.5v-3.5h6V16h-6zm13 0H13v-3.5h5.5V16zM13 11V7.5h5.5V11H13z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - tag - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M20.1 11.2l-6.7-6.7c-.1-.1-.3-.2-.5-.2H5c-.4-.1-.8.3-.8.7v7.8c0 .2.1.4.2.5l6.7 6.7c.2.2.5.4.7.5s.6.2.9.2c.3 0 .6-.1.9-.2.3-.1.5-.3.8-.5l5.6-5.6c.4-.4.7-1 .7-1.6.1-.6-.2-1.2-.6-1.6zM19 13.4L13.4 19c-.1.1-.2.1-.3.2-.2.1-.4.1-.6 0-.1 0-.2-.1-.3-.2l-6.5-6.5V5.8h6.8l6.5 6.5c.2.2.2.4.2.6 0 .1 0 .3-.2.5zM9 8c-.6 0-1 .4-1 1s.4 1 1 1 1-.4 1-1-.4-1-1-1z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M20.1 11.2l-6.7-6.7c-.1-.1-.3-.2-.5-.2H5c-.4-.1-.8.3-.8.7v7.8c0 .2.1.4.2.5l6.7 6.7c.2.2.5.4.7.5s.6.2.9.2c.3 0 .6-.1.9-.2.3-.1.5-.3.8-.5l5.6-5.6c.4-.4.7-1 .7-1.6.1-.6-.2-1.2-.6-1.6zM19 13.4L13.4 19c-.1.1-.2.1-.3.2-.2.1-.4.1-.6 0-.1 0-.2-.1-.3-.2l-6.5-6.5V5.8h6.8l6.5 6.5c.2.2.2.4.2.6 0 .1 0 .3-.2.5zM9 8c-.6 0-1 .4-1 1s.4 1 1 1 1-.4 1-1-.4-1-1-1z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M20.1 11.2l-6.7-6.7c-.1-.1-.3-.2-.5-.2H5c-.4-.1-.8.3-.8.7v7.8c0 .2.1.4.2.5l6.7 6.7c.2.2.5.4.7.5s.6.2.9.2c.3 0 .6-.1.9-.2.3-.1.5-.3.8-.5l5.6-5.6c.4-.4.7-1 .7-1.6.1-.6-.2-1.2-.6-1.6zM19 13.4L13.4 19c-.1.1-.2.1-.3.2-.2.1-.4.1-.6 0-.1 0-.2-.1-.3-.2l-6.5-6.5V5.8h6.8l6.5 6.5c.2.2.2.4.2.6 0 .1 0 .3-.2.5zM9 8c-.6 0-1 .4-1 1s.4 1 1 1 1-.4 1-1-.4-1-1-1z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - textColor - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13.23 15h1.9L11 4H9L5 15h1.88l1.07-3h4.18zm-1.53-4.54H8.51L10 5.6z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13.23 15h1.9L11 4H9L5 15h1.88l1.07-3h4.18zm-1.53-4.54H8.51L10 5.6z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13.23 15h1.9L11 4H9L5 15h1.88l1.07-3h4.18zm-1.53-4.54H8.51L10 5.6z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - title - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="https://www.w3.org/2000/svg" - > - <path - d="M5 4v3h5.5v12h3V7H19V4H5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="https://www.w3.org/2000/svg" - > - <path - d="M5 4v3h5.5v12h3V7H19V4H5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="https://www.w3.org/2000/svg" - > - <path - d="M5 4v3h5.5v12h3V7H19V4H5z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - trash - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M12 4h3c.6 0 1 .4 1 1v1H3V5c0-.6.5-1 1-1h3c.2-1.1 1.3-2 2.5-2s2.3.9 2.5 2zM8 4h3c-.2-.6-.9-1-1.5-1S8.2 3.4 8 4zM4 7h11l-.9 10.1c0 .5-.5.9-1 .9H5.9c-.5 0-.9-.4-1-.9L4 7z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M12 4h3c.6 0 1 .4 1 1v1H3V5c0-.6.5-1 1-1h3c.2-1.1 1.3-2 2.5-2s2.3.9 2.5 2zM8 4h3c-.2-.6-.9-1-1.5-1S8.2 3.4 8 4zM4 7h11l-.9 10.1c0 .5-.5.9-1 .9H5.9c-.5 0-.9-.4-1-.9L4 7z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M12 4h3c.6 0 1 .4 1 1v1H3V5c0-.6.5-1 1-1h3c.2-1.1 1.3-2 2.5-2s2.3.9 2.5 2zM8 4h3c-.2-.6-.9-1-1.5-1S8.2 3.4 8 4zM4 7h11l-.9 10.1c0 .5-.5.9-1 .9H5.9c-.5 0-.9-.4-1-.9L4 7z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - undo - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18.3 11.7c-.6-.6-1.4-.9-2.3-.9H6.7l2.9-3.3-1.1-1-4.5 5L8.5 16l1-1-2.7-2.7H16c.5 0 .9.2 1.3.5 1 1 1 3.4 1 4.5v.3h1.5v-.2c0-1.5 0-4.3-1.5-5.7z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18.3 11.7c-.6-.6-1.4-.9-2.3-.9H6.7l2.9-3.3-1.1-1-4.5 5L8.5 16l1-1-2.7-2.7H16c.5 0 .9.2 1.3.5 1 1 1 3.4 1 4.5v.3h1.5v-.2c0-1.5 0-4.3-1.5-5.7z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18.3 11.7c-.6-.6-1.4-.9-2.3-.9H6.7l2.9-3.3-1.1-1-4.5 5L8.5 16l1-1-2.7-2.7H16c.5 0 .9.2 1.3.5 1 1 1 3.4 1 4.5v.3h1.5v-.2c0-1.5 0-4.3-1.5-5.7z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - update - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M10.2 3.28c3.53 0 6.43 2.61 6.92 6h2.08l-3.5 4-3.5-4h2.32c-.45-1.97-2.21-3.45-4.32-3.45-1.45 0-2.73.71-3.54 1.78L4.95 5.66C6.23 4.2 8.11 3.28 10.2 3.28zm-.4 13.44c-3.52 0-6.43-2.61-6.92-6H.8l3.5-4c1.17 1.33 2.33 2.67 3.5 4H5.48c.45 1.97 2.21 3.45 4.32 3.45 1.45 0 2.73-.71 3.54-1.78l1.71 1.95c-1.28 1.46-3.15 2.38-5.25 2.38z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M10.2 3.28c3.53 0 6.43 2.61 6.92 6h2.08l-3.5 4-3.5-4h2.32c-.45-1.97-2.21-3.45-4.32-3.45-1.45 0-2.73.71-3.54 1.78L4.95 5.66C6.23 4.2 8.11 3.28 10.2 3.28zm-.4 13.44c-3.52 0-6.43-2.61-6.92-6H.8l3.5-4c1.17 1.33 2.33 2.67 3.5 4H5.48c.45 1.97 2.21 3.45 4.32 3.45 1.45 0 2.73-.71 3.54-1.78l1.71 1.95c-1.28 1.46-3.15 2.38-5.25 2.38z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M10.2 3.28c3.53 0 6.43 2.61 6.92 6h2.08l-3.5 4-3.5-4h2.32c-.45-1.97-2.21-3.45-4.32-3.45-1.45 0-2.73.71-3.54 1.78L4.95 5.66C6.23 4.2 8.11 3.28 10.2 3.28zm-.4 13.44c-3.52 0-6.43-2.61-6.92-6H.8l3.5-4c1.17 1.33 2.33 2.67 3.5 4H5.48c.45 1.97 2.21 3.45 4.32 3.45 1.45 0 2.73-.71 3.54-1.78l1.71 1.95c-1.28 1.46-3.15 2.38-5.25 2.38z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - upload - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18.5 15v3.5H13V6.7l4.5 4.1 1-1.1-5.7-5.3-.6.6-.5-.5-5.2 5.2 1 1.1 4-4v11.7h-6V15H4v5h16v-5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18.5 15v3.5H13V6.7l4.5 4.1 1-1.1-5.7-5.3-.6.6-.5-.5-5.2 5.2 1 1.1 4-4v11.7h-6V15H4v5h16v-5z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18.5 15v3.5H13V6.7l4.5 4.1 1-1.1-5.7-5.3-.6.6-.5-.5-5.2 5.2 1 1.1 4-4v11.7h-6V15H4v5h16v-5z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - verse - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M17.8 2l-.9.3c-.1 0-3.6 1-5.2 2.1C10 5.5 9.3 6.5 8.9 7.1c-.6.9-1.7 4.7-1.7 6.3l-.9 2.3c-.2.4 0 .8.4 1 .1 0 .2.1.3.1.3 0 .6-.2.7-.5l.6-1.5c.3 0 .7-.1 1.2-.2.7-.1 1.4-.3 2.2-.5.8-.2 1.6-.5 2.4-.8.7-.3 1.4-.7 1.9-1.2s.8-1.2 1-1.9c.2-.7.3-1.6.4-2.4.1-.8.1-1.7.2-2.5 0-.8.1-1.5.2-2.1V2zm-1.9 5.6c-.1.8-.2 1.5-.3 2.1-.2.6-.4 1-.6 1.3-.3.3-.8.6-1.4.9-.7.3-1.4.5-2.2.8-.6.2-1.3.3-1.8.4L15 7.5c.3-.3.6-.7 1-1.1 0 .4 0 .8-.1 1.2zM6 20h8v-1.5H6V20z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M17.8 2l-.9.3c-.1 0-3.6 1-5.2 2.1C10 5.5 9.3 6.5 8.9 7.1c-.6.9-1.7 4.7-1.7 6.3l-.9 2.3c-.2.4 0 .8.4 1 .1 0 .2.1.3.1.3 0 .6-.2.7-.5l.6-1.5c.3 0 .7-.1 1.2-.2.7-.1 1.4-.3 2.2-.5.8-.2 1.6-.5 2.4-.8.7-.3 1.4-.7 1.9-1.2s.8-1.2 1-1.9c.2-.7.3-1.6.4-2.4.1-.8.1-1.7.2-2.5 0-.8.1-1.5.2-2.1V2zm-1.9 5.6c-.1.8-.2 1.5-.3 2.1-.2.6-.4 1-.6 1.3-.3.3-.8.6-1.4.9-.7.3-1.4.5-2.2.8-.6.2-1.3.3-1.8.4L15 7.5c.3-.3.6-.7 1-1.1 0 .4 0 .8-.1 1.2zM6 20h8v-1.5H6V20z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M17.8 2l-.9.3c-.1 0-3.6 1-5.2 2.1C10 5.5 9.3 6.5 8.9 7.1c-.6.9-1.7 4.7-1.7 6.3l-.9 2.3c-.2.4 0 .8.4 1 .1 0 .2.1.3.1.3 0 .6-.2.7-.5l.6-1.5c.3 0 .7-.1 1.2-.2.7-.1 1.4-.3 2.2-.5.8-.2 1.6-.5 2.4-.8.7-.3 1.4-.7 1.9-1.2s.8-1.2 1-1.9c.2-.7.3-1.6.4-2.4.1-.8.1-1.7.2-2.5 0-.8.1-1.5.2-2.1V2zm-1.9 5.6c-.1.8-.2 1.5-.3 2.1-.2.6-.4 1-.6 1.3-.3.3-.8.6-1.4.9-.7.3-1.4.5-2.2.8-.6.2-1.3.3-1.8.4L15 7.5c.3-.3.6-.7 1-1.1 0 .4 0 .8-.1 1.2zM6 20h8v-1.5H6V20z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - video - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18.7 3H5.3C4 3 3 4 3 5.3v13.4C3 20 4 21 5.3 21h13.4c1.3 0 2.3-1 2.3-2.3V5.3C21 4 20 3 18.7 3zm.8 15.7c0 .4-.4.8-.8.8H5.3c-.4 0-.8-.4-.8-.8V5.3c0-.4.4-.8.8-.8h13.4c.4 0 .8.4.8.8v13.4zM10 15l5-3-5-3v6z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18.7 3H5.3C4 3 3 4 3 5.3v13.4C3 20 4 21 5.3 21h13.4c1.3 0 2.3-1 2.3-2.3V5.3C21 4 20 3 18.7 3zm.8 15.7c0 .4-.4.8-.8.8H5.3c-.4 0-.8-.4-.8-.8V5.3c0-.4.4-.8.8-.8h13.4c.4 0 .8.4.8.8v13.4zM10 15l5-3-5-3v6z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18.7 3H5.3C4 3 3 4 3 5.3v13.4C3 20 4 21 5.3 21h13.4c1.3 0 2.3-1 2.3-2.3V5.3C21 4 20 3 18.7 3zm.8 15.7c0 .4-.4.8-.8.8H5.3c-.4 0-.8-.4-.8-.8V5.3c0-.4.4-.8.8-.8h13.4c.4 0 .8.4.8.8v13.4zM10 15l5-3-5-3v6z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - widget - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="0 0 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M7 11h2v2H7v-2zm14-5v14l-2 2H5l-2-2V6l2-2h1V2h2v2h8V2h2v2h1l2 2zM5 8h14V6H5v2zm14 12V10H5v10h14zm-4-7h2v-2h-2v2zm-4 0h2v-2h-2v2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="0 0 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M7 11h2v2H7v-2zm14-5v14l-2 2H5l-2-2V6l2-2h1V2h2v2h8V2h2v2h1l2 2zM5 8h14V6H5v2zm14 12V10H5v10h14zm-4-7h2v-2h-2v2zm-4 0h2v-2h-2v2z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="0 0 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M7 11h2v2H7v-2zm14-5v14l-2 2H5l-2-2V6l2-2h1V2h2v2h8V2h2v2h1l2 2zM5 8h14V6H5v2zm14 12V10H5v10h14zm-4-7h2v-2h-2v2zm-4 0h2v-2h-2v2z" - /> - </svg> - </div> - <div - style={ - Object { - "alignItems": "center", - "display": "flex", - } - } - > - <strong - style={ - Object { - "width": "120px", - } - } - > - wordpress - </strong> - <svg - aria-hidden="true" - focusable="false" - height={24} - role="img" - viewBox="-2 -2 24 24" - width={24} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M20 10c0-5.51-4.49-10-10-10C4.48 0 0 4.49 0 10c0 5.52 4.48 10 10 10 5.51 0 10-4.48 10-10zM7.78 15.37L4.37 6.22c.55-.02 1.17-.08 1.17-.08.5-.06.44-1.13-.06-1.11 0 0-1.45.11-2.37.11-.18 0-.37 0-.58-.01C4.12 2.69 6.87 1.11 10 1.11c2.33 0 4.45.87 6.05 2.34-.68-.11-1.65.39-1.65 1.58 0 .74.45 1.36.9 2.1.35.61.55 1.36.55 2.46 0 1.49-1.4 5-1.4 5l-3.03-8.37c.54-.02.82-.17.82-.17.5-.05.44-1.25-.06-1.22 0 0-1.44.12-2.38.12-.87 0-2.33-.12-2.33-.12-.5-.03-.56 1.2-.06 1.22l.92.08 1.26 3.41zM17.41 10c.24-.64.74-1.87.43-4.25.7 1.29 1.05 2.71 1.05 4.25 0 3.29-1.73 6.24-4.4 7.78.97-2.59 1.94-5.2 2.92-7.78zM6.1 18.09C3.12 16.65 1.11 13.53 1.11 10c0-1.3.23-2.48.72-3.59C3.25 10.3 4.67 14.2 6.1 18.09zm4.03-6.63l2.58 6.98c-.86.29-1.76.45-2.71.45-.79 0-1.57-.11-2.29-.33.81-2.38 1.62-4.74 2.42-7.1z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={36} - role="img" - viewBox="-2 -2 24 24" - width={36} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M20 10c0-5.51-4.49-10-10-10C4.48 0 0 4.49 0 10c0 5.52 4.48 10 10 10 5.51 0 10-4.48 10-10zM7.78 15.37L4.37 6.22c.55-.02 1.17-.08 1.17-.08.5-.06.44-1.13-.06-1.11 0 0-1.45.11-2.37.11-.18 0-.37 0-.58-.01C4.12 2.69 6.87 1.11 10 1.11c2.33 0 4.45.87 6.05 2.34-.68-.11-1.65.39-1.65 1.58 0 .74.45 1.36.9 2.1.35.61.55 1.36.55 2.46 0 1.49-1.4 5-1.4 5l-3.03-8.37c.54-.02.82-.17.82-.17.5-.05.44-1.25-.06-1.22 0 0-1.44.12-2.38.12-.87 0-2.33-.12-2.33-.12-.5-.03-.56 1.2-.06 1.22l.92.08 1.26 3.41zM17.41 10c.24-.64.74-1.87.43-4.25.7 1.29 1.05 2.71 1.05 4.25 0 3.29-1.73 6.24-4.4 7.78.97-2.59 1.94-5.2 2.92-7.78zM6.1 18.09C3.12 16.65 1.11 13.53 1.11 10c0-1.3.23-2.48.72-3.59C3.25 10.3 4.67 14.2 6.1 18.09zm4.03-6.63l2.58 6.98c-.86.29-1.76.45-2.71.45-.79 0-1.57-.11-2.29-.33.81-2.38 1.62-4.74 2.42-7.1z" - /> - </svg> - <svg - aria-hidden="true" - focusable="false" - height={48} - role="img" - viewBox="-2 -2 24 24" - width={48} - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M20 10c0-5.51-4.49-10-10-10C4.48 0 0 4.49 0 10c0 5.52 4.48 10 10 10 5.51 0 10-4.48 10-10zM7.78 15.37L4.37 6.22c.55-.02 1.17-.08 1.17-.08.5-.06.44-1.13-.06-1.11 0 0-1.45.11-2.37.11-.18 0-.37 0-.58-.01C4.12 2.69 6.87 1.11 10 1.11c2.33 0 4.45.87 6.05 2.34-.68-.11-1.65.39-1.65 1.58 0 .74.45 1.36.9 2.1.35.61.55 1.36.55 2.46 0 1.49-1.4 5-1.4 5l-3.03-8.37c.54-.02.82-.17.82-.17.5-.05.44-1.25-.06-1.22 0 0-1.44.12-2.38.12-.87 0-2.33-.12-2.33-.12-.5-.03-.56 1.2-.06 1.22l.92.08 1.26 3.41zM17.41 10c.24-.64.74-1.87.43-4.25.7 1.29 1.05 2.71 1.05 4.25 0 3.29-1.73 6.24-4.4 7.78.97-2.59 1.94-5.2 2.92-7.78zM6.1 18.09C3.12 16.65 1.11 13.53 1.11 10c0-1.3.23-2.48.72-3.59C3.25 10.3 4.67 14.2 6.1 18.09zm4.03-6.63l2.58 6.98c-.86.29-1.76.45-2.71.45-.79 0-1.57-.11-2.29-.33.81-2.38 1.62-4.74 2.42-7.1z" - /> - </svg> - </div> -</div> -`; diff --git a/storybook/test/index.js b/storybook/test/index.js deleted file mode 100644 index 8752847743e0b8..00000000000000 --- a/storybook/test/index.js +++ /dev/null @@ -1,32 +0,0 @@ -/** - * External dependencies - */ -import initStoryshots, { - snapshotWithOptions, -} from '@storybook/addon-storyshots'; -import path from 'path'; - -initStoryshots( { - configPath: path.resolve( __dirname, '../' ), - test: snapshotWithOptions( ( story ) => ( { - // We need to mock refs for some stories which use them. - // @see https://reactjs.org/blog/2016/11/16/react-v15.4.0.html#mocking-refs-for-snapshot-testing - // @see https://github.com/storybookjs/storybook/tree/master/addons/storyshots/storyshots-core#using-createnodemock-to-mock-refs - createNodeMock: ( element ) => { - const currentElement = - element.type && document.createElement( element.type ); - - if ( story.kind === 'Components/ClipboardButton' ) { - currentElement.appendChild( - document.createElement( 'button' ) - ); - } - if ( story.kind === 'Components/Popover' ) { - const parentElement = document.createElement( 'div' ); - parentElement.appendChild( currentElement ); - } - - return currentElement; - }, - } ) ), -} ); diff --git a/test/integration/full-content/server-registered.json b/test/integration/full-content/server-registered.json index 95514917078471..a17d53a4f227c7 100644 --- a/test/integration/full-content/server-registered.json +++ b/test/integration/full-content/server-registered.json @@ -1 +1 @@ -{"core\/archives":{"attributes":{"align":{"type":"string","enum":["left","center","right","wide","full"]},"className":{"type":"string"},"displayAsDropdown":{"type":"boolean","default":false},"showPostCounts":{"type":"boolean","default":false}}},"core\/block":{"attributes":{"ref":{"type":"number"}}},"core\/calendar":{"attributes":{"align":{"type":"string","enum":["left","center","right","wide","full"]},"className":{"type":"string"},"month":{"type":"integer"},"year":{"type":"integer"}}},"core\/categories":{"attributes":{"align":{"type":"string","enum":["left","center","right","wide","full"]},"className":{"type":"string"},"displayAsDropdown":{"type":"boolean","default":false},"showHierarchy":{"type":"boolean","default":false},"showPostCounts":{"type":"boolean","default":false}}},"core\/latest-comments":{"attributes":{"align":{"type":"string","enum":["left","center","right","wide","full"]},"className":{"type":"string"},"commentsToShow":{"type":"number","default":5,"minimum":1,"maximum":100},"displayAvatar":{"type":"boolean","default":true},"displayDate":{"type":"boolean","default":true},"displayExcerpt":{"type":"boolean","default":true}}},"core\/latest-posts":{"attributes":{"align":{"type":"string","enum":["left","center","right","wide","full"]},"className":{"type":"string"},"categories":{"type":"string"},"postsToShow":{"type":"number","default":5},"displayPostContent":{"type":"boolean","default":false},"displayPostContentRadio":{"type":"string","default":"excerpt"},"excerptLength":{"type":"number","default":55},"displayPostDate":{"type":"boolean","default":false},"postLayout":{"type":"string","default":"list"},"columns":{"type":"number","default":3},"order":{"type":"string","default":"desc"},"orderBy":{"type":"string","default":"date"},"displayFeaturedImage":{"type":"boolean","default":false},"featuredImageAlign":{"type":"string","enum":["left","center","right"]},"featuredImageSizeSlug":{"type":"string","default":"thumbnail"},"featuredImageSizeWidth":{"type":"number","default":null},"featuredImageSizeHeight":{"type":"number","default":null}}},"core\/legacy-widget":{"attributes":{"widgetClass":{"type":"string"},"id":{"type":"string"},"idBase":{"type":"string"},"number":{"type":"number"},"instance":{"type":"object"}}},"core\/navigation":{"attributes":{"className":{"type":"string"},"textColor":{"type":"string"},"customTextColor":{"type":"string"},"rgbTextColor":{"type":"string"},"backgroundColor":{"type":"string"},"customBackgroundColor":{"type":"string"},"rgbBackgroundColor":{"type":"string"},"fontSize":{"type":"string"},"customFontSize":{"type":"number"},"itemsJustification":{"type":"string"},"showSubmenuIcon":{"type":"boolean","default":true}}},"core\/post-comments-count":{"attributes":{"className":{"type":"string"}}},"core\/post-excerpt":{"attributes":{"wordCount":{"type":"number","default":55},"moreText":{"type":"string"},"showMoreOnNewLine":{"type":"boolean","default":true}}},"core\/rss":{"attributes":{"align":{"type":"string","enum":["left","center","right","wide","full"]},"className":{"type":"string"},"columns":{"type":"number","default":2},"blockLayout":{"type":"string","default":"list"},"feedURL":{"type":"string","default":""},"itemsToShow":{"type":"number","default":5},"displayExcerpt":{"type":"boolean","default":false},"displayAuthor":{"type":"boolean","default":false},"displayDate":{"type":"boolean","default":false},"excerptLength":{"type":"number","default":55}}},"core\/search":{"attributes":{"align":{"type":"string","enum":["left","center","right","wide","full"]},"className":{"type":"string"},"label":{"type":"string","default":"Search"},"placeholder":{"type":"string","default":""},"buttonText":{"type":"string","default":"Search"}}},"core\/tag-cloud":{"attributes":{"align":{"type":"string","enum":["left","center","right","wide","full"]},"className":{"type":"string"},"taxonomy":{"type":"string","default":"post_tag"},"showTagCounts":{"type":"boolean","default":false}}},"core\/template-part":{"attributes":{"postId":{"type":"number"},"slug":{"type":"string"},"theme":{"type":"string"}}}} +{"core\/archives":{"attributes":{"align":{"type":"string","enum":["left","center","right","wide","full"]},"className":{"type":"string"},"displayAsDropdown":{"type":"boolean","default":false},"showPostCounts":{"type":"boolean","default":false}}},"core\/block":{"attributes":{"ref":{"type":"number"}}},"core\/calendar":{"attributes":{"align":{"type":"string","enum":["left","center","right","wide","full"]},"className":{"type":"string"},"month":{"type":"integer"},"year":{"type":"integer"}}},"core\/categories":{"attributes":{"align":{"type":"string","enum":["left","center","right","wide","full"]},"className":{"type":"string"},"displayAsDropdown":{"type":"boolean","default":false},"showHierarchy":{"type":"boolean","default":false},"showPostCounts":{"type":"boolean","default":false}}},"core\/latest-comments":{"attributes":{"align":{"type":"string","enum":["left","center","right","wide","full"]},"className":{"type":"string"},"commentsToShow":{"type":"number","default":5,"minimum":1,"maximum":100},"displayAvatar":{"type":"boolean","default":true},"displayDate":{"type":"boolean","default":true},"displayExcerpt":{"type":"boolean","default":true}}},"core\/legacy-widget":{"attributes":{"widgetClass":{"type":"string"},"id":{"type":"string"},"idBase":{"type":"string"},"number":{"type":"number"},"instance":{"type":"object"}}},"core\/navigation":{"attributes":{"className":{"type":"string"},"textColor":{"type":"string"},"customTextColor":{"type":"string"},"rgbTextColor":{"type":"string"},"backgroundColor":{"type":"string"},"customBackgroundColor":{"type":"string"},"rgbBackgroundColor":{"type":"string"},"fontSize":{"type":"string"},"customFontSize":{"type":"number"},"itemsJustification":{"type":"string"},"showSubmenuIcon":{"type":"boolean","default":true}}},"core\/rss":{"attributes":{"align":{"type":"string","enum":["left","center","right","wide","full"]},"className":{"type":"string"},"columns":{"type":"number","default":2},"blockLayout":{"type":"string","default":"list"},"feedURL":{"type":"string","default":""},"itemsToShow":{"type":"number","default":5},"displayExcerpt":{"type":"boolean","default":false},"displayAuthor":{"type":"boolean","default":false},"displayDate":{"type":"boolean","default":false},"excerptLength":{"type":"number","default":55}}},"core\/search":{"attributes":{"align":{"type":"string","enum":["left","center","right","wide","full"]},"className":{"type":"string"},"label":{"type":"string","default":"Search"},"placeholder":{"type":"string","default":""},"buttonText":{"type":"string","default":"Search"}}},"core\/tag-cloud":{"attributes":{"align":{"type":"string","enum":["left","center","right","wide","full"]},"className":{"type":"string"},"taxonomy":{"type":"string","default":"post_tag"},"showTagCounts":{"type":"boolean","default":false}}},"core\/template-part":{"attributes":{"postId":{"type":"number"},"slug":{"type":"string"},"theme":{"type":"string"}}}} diff --git a/test/native/__mocks__/styleMock.js b/test/native/__mocks__/styleMock.js index 6a1481e6fe388f..55fa4dd0a954c9 100644 --- a/test/native/__mocks__/styleMock.js +++ b/test/native/__mocks__/styleMock.js @@ -90,4 +90,7 @@ module.exports = { blockBorder: { width: 1, }, + defaultBlock: { + marginTop: 16, + }, }; diff --git a/test/native/setup.js b/test/native/setup.js index c3c9fda6d74a57..2728e05fbe2120 100644 --- a/test/native/setup.js +++ b/test/native/setup.js @@ -13,6 +13,7 @@ jest.mock( '@wordpress/react-native-bridge', () => { subscribeSetFocusOnTitle: jest.fn(), subscribeUpdateHtml: jest.fn(), subscribeMediaAppend: jest.fn(), + subscribeAndroidModalClosed: jest.fn(), subscribePreferredColorScheme: () => 'light', editorDidMount: jest.fn(), editorDidAutosave: jest.fn(), diff --git a/tsconfig.base.json b/tsconfig.base.json new file mode 100644 index 00000000000000..08e7a57fab1e39 --- /dev/null +++ b/tsconfig.base.json @@ -0,0 +1,47 @@ +{ + "compilerOptions": { + "allowJs": true, + "checkJs": true, + "allowSyntheticDefaultImports": true, + "jsx": "preserve", + "target": "esnext", + "types": ["react", "node", "requestidlecallback"], + "module": "esnext", + "lib": [ "dom", "esnext" ], + "declaration": true, + "declarationMap": true, + "composite": true, + "emitDeclarationOnly": true, + "isolatedModules": true, + + /* Strict Type-Checking Options */ + "strict": true, + "strictNullChecks": true, + "noImplicitAny": true, + + /* Additional Checks */ + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + + /* Module Resolution Options */ + "moduleResolution": "node", + + /* This needs to be false so our types are possible to consume without setting this */ + "esModuleInterop": false, + "resolveJsonModule": true, + + "typeRoots": [ "./node_modules/@types" ] + }, + "exclude": [ + "**/benchmark", + "**/test/**", + "**/build/**", + "**/build-*/**", + "**/*.android.js", + "**/*.ios.js", + "**/*.native.js", + "./packages/**/react-native-*/**" + ] +} diff --git a/tsconfig.json b/tsconfig.json index 5881a6f4f13a6d..7f31d9ad53e770 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,53 +1,27 @@ { - "compilerOptions": { - "allowJs": true, - "allowSyntheticDefaultImports": true, - "checkJs": true, - "jsx": "preserve", - "lib": ["dom", "esnext"], - "module": "commonjs", - "noEmit": true, - "resolveJsonModule": true, - "target": "esnext", - "types": ["react", "node", "jest", "requestidlecallback"], + "references": [ + { "path": "bin" }, + { "path": "packages/a11y" }, + { "path": "packages/autop" }, + { "path": "packages/blob" }, + { "path": "packages/block-editor" }, + { "path": "packages/dom-ready" }, + { "path": "packages/escape-html" }, + { "path": "packages/html-entities" }, + { "path": "packages/i18n" }, + { "path": "packages/is-shallow-equal" }, + { "path": "packages/prettier-config" }, + { "path": "packages/priority-queue" }, + { "path": "packages/project-management-automation" }, + { "path": "packages/token-list" }, + { "path": "packages/url" }, + { "path": "packages/warning" } - /* Project Imports */ - "baseUrl": ".", - "paths": { - "@wordpress/*": [ - "packages/*/index.js", - "packages/*/src/index.js" - ] - }, - - /* Strict Type-Checking Options */ - "strict": true, /* Enable all strict type-checking options. */ - "strictNullChecks": true, - "noImplicitAny": false, /* Raise error on expressions and declarations with an implied 'any' type. */ - - /* Additional Checks */ - "noUnusedLocals": true, /* Report errors on unused locals. */ - "noUnusedParameters": true, /* Report errors on unused parameters. */ - "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ - "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ - }, - "include": [ - "./packages/a11y/**/*.js", - "./packages/blob/**/*.js", - "./packages/dom-ready/**/*.js", - "./packages/i18n/**/*.js", - "./packages/is-shallow-equal/**/*.js", - "./packages/priority-queue/**/*.js", - "./packages/project-management-automation/**/*.js", - "./packages/token-list/**/*.js", - "./packages/url/src/**/*.js", - "./packages/warning/**/*.js", + // Temporarily disabled due to conflicts with 3rd party DefinitelyTyped types + // See https://github.com/WordPress/gutenberg/pull/21613 + // { "path": "packages/element" }, + // { "path": "packages/icons" }, + // { "path": "packages/primitives" } ], - "exclude": [ - "./packages/*/benchmark", - "./packages/**/test/**", - "./packages/**/build/**", - "./packages/**/build-module/**", - "./packages/**/react-native-*/**" - ] + "files": [] } diff --git a/webpack.config.js b/webpack.config.js index 9f2b7b959839bb..96b887d908ba23 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -13,7 +13,9 @@ const { basename, sep } = require( 'path' ); const CustomTemplatedPathPlugin = require( '@wordpress/custom-templated-path-webpack-plugin' ); const LibraryExportDefaultPlugin = require( '@wordpress/library-export-default-webpack-plugin' ); const DependencyExtractionWebpackPlugin = require( '@wordpress/dependency-extraction-webpack-plugin' ); -const { camelCaseDash } = require( '@wordpress/scripts/utils' ); +const { + camelCaseDash, +} = require( '@wordpress/dependency-extraction-webpack-plugin/util' ); /** * Internal dependencies @@ -26,7 +28,7 @@ const { } = process.env; const WORDPRESS_NAMESPACE = '@wordpress/'; -const BUNDLED_PACKAGES = [ '@wordpress/icons' ]; +const BUNDLED_PACKAGES = [ '@wordpress/icons', '@wordpress/interface' ]; const gutenbergPackages = Object.keys( dependencies ) .filter( @@ -189,5 +191,8 @@ module.exports = { ] ), new DependencyExtractionWebpackPlugin( { injectPolyfill: true } ), ], + watchOptions: { + ignored: '!packages/*/!(src)/**/*', + }, devtool, };