diff --git a/.yarn/offline-mirror/@babel-core-7.5.5.tgz b/.yarn/offline-mirror/@babel-core-7.5.5.tgz new file mode 100644 index 000000000000..273bde99e7c4 Binary files /dev/null and b/.yarn/offline-mirror/@babel-core-7.5.5.tgz differ diff --git a/.yarn/offline-mirror/@babel-helper-define-map-7.5.5.tgz b/.yarn/offline-mirror/@babel-helper-define-map-7.5.5.tgz new file mode 100644 index 000000000000..500309195d00 Binary files /dev/null and b/.yarn/offline-mirror/@babel-helper-define-map-7.5.5.tgz differ diff --git a/.yarn/offline-mirror/@babel-helper-member-expression-to-functions-7.5.5.tgz b/.yarn/offline-mirror/@babel-helper-member-expression-to-functions-7.5.5.tgz new file mode 100644 index 000000000000..7d2471ee0f98 Binary files /dev/null and b/.yarn/offline-mirror/@babel-helper-member-expression-to-functions-7.5.5.tgz differ diff --git a/.yarn/offline-mirror/@babel-helper-replace-supers-7.5.5.tgz b/.yarn/offline-mirror/@babel-helper-replace-supers-7.5.5.tgz new file mode 100644 index 000000000000..b34ac479030e Binary files /dev/null and b/.yarn/offline-mirror/@babel-helper-replace-supers-7.5.5.tgz differ diff --git a/.yarn/offline-mirror/@babel-plugin-transform-block-scoping-7.5.5.tgz b/.yarn/offline-mirror/@babel-plugin-transform-block-scoping-7.5.5.tgz new file mode 100644 index 000000000000..1e4095c84db6 Binary files /dev/null and b/.yarn/offline-mirror/@babel-plugin-transform-block-scoping-7.5.5.tgz differ diff --git a/.yarn/offline-mirror/@babel-plugin-transform-classes-7.5.5.tgz b/.yarn/offline-mirror/@babel-plugin-transform-classes-7.5.5.tgz new file mode 100644 index 000000000000..addfe69d7eaa Binary files /dev/null and b/.yarn/offline-mirror/@babel-plugin-transform-classes-7.5.5.tgz differ diff --git a/.yarn/offline-mirror/@babel-plugin-transform-object-super-7.5.5.tgz b/.yarn/offline-mirror/@babel-plugin-transform-object-super-7.5.5.tgz new file mode 100644 index 000000000000..0bcbc777cd54 Binary files /dev/null and b/.yarn/offline-mirror/@babel-plugin-transform-object-super-7.5.5.tgz differ diff --git a/.yarn/offline-mirror/@babel-preset-env-7.5.5.tgz b/.yarn/offline-mirror/@babel-preset-env-7.5.5.tgz new file mode 100644 index 000000000000..90d48986d26f Binary files /dev/null and b/.yarn/offline-mirror/@babel-preset-env-7.5.5.tgz differ diff --git a/.yarn/offline-mirror/@types-node-12.7.3.tgz b/.yarn/offline-mirror/@types-node-12.7.3.tgz new file mode 100644 index 000000000000..ad1693949a62 Binary files /dev/null and b/.yarn/offline-mirror/@types-node-12.7.3.tgz differ diff --git a/.yarn/offline-mirror/acorn-7.0.0.tgz b/.yarn/offline-mirror/acorn-7.0.0.tgz new file mode 100644 index 000000000000..a2964fe07e5d Binary files /dev/null and b/.yarn/offline-mirror/acorn-7.0.0.tgz differ diff --git a/.yarn/offline-mirror/ajv-6.10.2.tgz b/.yarn/offline-mirror/ajv-6.10.2.tgz new file mode 100644 index 000000000000..5d591842d429 Binary files /dev/null and b/.yarn/offline-mirror/ajv-6.10.2.tgz differ diff --git a/.yarn/offline-mirror/ajv-keywords-3.4.1.tgz b/.yarn/offline-mirror/ajv-keywords-3.4.1.tgz new file mode 100644 index 000000000000..a6d89890319a Binary files /dev/null and b/.yarn/offline-mirror/ajv-keywords-3.4.1.tgz differ diff --git a/.yarn/offline-mirror/autoprefixer-9.6.1.tgz b/.yarn/offline-mirror/autoprefixer-9.6.1.tgz new file mode 100644 index 000000000000..d37d08e7e69e Binary files /dev/null and b/.yarn/offline-mirror/autoprefixer-9.6.1.tgz differ diff --git a/.yarn/offline-mirror/browserslist-4.7.0.tgz b/.yarn/offline-mirror/browserslist-4.7.0.tgz new file mode 100644 index 000000000000..d2b013dc7857 Binary files /dev/null and b/.yarn/offline-mirror/browserslist-4.7.0.tgz differ diff --git a/.yarn/offline-mirror/caniuse-lite-1.0.30000989.tgz b/.yarn/offline-mirror/caniuse-lite-1.0.30000989.tgz new file mode 100644 index 000000000000..a4257f03e49c Binary files /dev/null and b/.yarn/offline-mirror/caniuse-lite-1.0.30000989.tgz differ diff --git a/.yarn/offline-mirror/clone-deep-4.0.1.tgz b/.yarn/offline-mirror/clone-deep-4.0.1.tgz new file mode 100644 index 000000000000..5ade210df125 Binary files /dev/null and b/.yarn/offline-mirror/clone-deep-4.0.1.tgz differ diff --git a/.yarn/offline-mirror/css-loader-3.2.0.tgz b/.yarn/offline-mirror/css-loader-3.2.0.tgz new file mode 100644 index 000000000000..104aa6832d00 Binary files /dev/null and b/.yarn/offline-mirror/css-loader-3.2.0.tgz differ diff --git a/.yarn/offline-mirror/electron-to-chromium-1.3.250.tgz b/.yarn/offline-mirror/electron-to-chromium-1.3.250.tgz new file mode 100644 index 000000000000..b61df2d9745f Binary files /dev/null and b/.yarn/offline-mirror/electron-to-chromium-1.3.250.tgz differ diff --git a/.yarn/offline-mirror/is-reference-1.1.3.tgz b/.yarn/offline-mirror/is-reference-1.1.3.tgz new file mode 100644 index 000000000000..0a5402d73e15 Binary files /dev/null and b/.yarn/offline-mirror/is-reference-1.1.3.tgz differ diff --git a/.yarn/offline-mirror/node-releases-1.1.29.tgz b/.yarn/offline-mirror/node-releases-1.1.29.tgz new file mode 100644 index 000000000000..867e31cd3b59 Binary files /dev/null and b/.yarn/offline-mirror/node-releases-1.1.29.tgz differ diff --git a/.yarn/offline-mirror/postcss-modules-local-by-default-3.0.2.tgz b/.yarn/offline-mirror/postcss-modules-local-by-default-3.0.2.tgz new file mode 100644 index 000000000000..de818ad66eaa Binary files /dev/null and b/.yarn/offline-mirror/postcss-modules-local-by-default-3.0.2.tgz differ diff --git a/.yarn/offline-mirror/postcss-modules-values-3.0.0.tgz b/.yarn/offline-mirror/postcss-modules-values-3.0.0.tgz new file mode 100644 index 000000000000..80c45fdf8036 Binary files /dev/null and b/.yarn/offline-mirror/postcss-modules-values-3.0.0.tgz differ diff --git a/.yarn/offline-mirror/react-16.9.0.tgz b/.yarn/offline-mirror/react-16.9.0.tgz new file mode 100644 index 000000000000..0e82cf4e2d1e Binary files /dev/null and b/.yarn/offline-mirror/react-16.9.0.tgz differ diff --git a/.yarn/offline-mirror/react-dom-16.9.0.tgz b/.yarn/offline-mirror/react-dom-16.9.0.tgz new file mode 100644 index 000000000000..37e085ad3dcb Binary files /dev/null and b/.yarn/offline-mirror/react-dom-16.9.0.tgz differ diff --git a/.yarn/offline-mirror/resolve-1.12.0.tgz b/.yarn/offline-mirror/resolve-1.12.0.tgz new file mode 100644 index 000000000000..26739036dbf6 Binary files /dev/null and b/.yarn/offline-mirror/resolve-1.12.0.tgz differ diff --git a/.yarn/offline-mirror/rollup-1.20.3.tgz b/.yarn/offline-mirror/rollup-1.20.3.tgz new file mode 100644 index 000000000000..aa1440f57625 Binary files /dev/null and b/.yarn/offline-mirror/rollup-1.20.3.tgz differ diff --git a/.yarn/offline-mirror/rollup-plugin-commonjs-10.1.0.tgz b/.yarn/offline-mirror/rollup-plugin-commonjs-10.1.0.tgz new file mode 100644 index 000000000000..ebda5ebdf23c Binary files /dev/null and b/.yarn/offline-mirror/rollup-plugin-commonjs-10.1.0.tgz differ diff --git a/.yarn/offline-mirror/rollup-plugin-node-resolve-5.2.0.tgz b/.yarn/offline-mirror/rollup-plugin-node-resolve-5.2.0.tgz new file mode 100644 index 000000000000..8e78e0afa74b Binary files /dev/null and b/.yarn/offline-mirror/rollup-plugin-node-resolve-5.2.0.tgz differ diff --git a/.yarn/offline-mirror/sass-loader-8.0.0.tgz b/.yarn/offline-mirror/sass-loader-8.0.0.tgz new file mode 100644 index 000000000000..37a21776e442 Binary files /dev/null and b/.yarn/offline-mirror/sass-loader-8.0.0.tgz differ diff --git a/.yarn/offline-mirror/schema-utils-2.2.0.tgz b/.yarn/offline-mirror/schema-utils-2.2.0.tgz new file mode 100644 index 000000000000..b6fc48e1acb0 Binary files /dev/null and b/.yarn/offline-mirror/schema-utils-2.2.0.tgz differ diff --git a/.yarn/offline-mirror/shallow-clone-3.0.1.tgz b/.yarn/offline-mirror/shallow-clone-3.0.1.tgz new file mode 100644 index 000000000000..1b95b31d1e09 Binary files /dev/null and b/.yarn/offline-mirror/shallow-clone-3.0.1.tgz differ diff --git a/.yarn/offline-mirror/style-loader-1.0.0.tgz b/.yarn/offline-mirror/style-loader-1.0.0.tgz new file mode 100644 index 000000000000..d8bbf43d0c59 Binary files /dev/null and b/.yarn/offline-mirror/style-loader-1.0.0.tgz differ diff --git a/packages/react-hooks/.npmignore b/packages/react-hooks/.npmignore new file mode 100644 index 000000000000..81ba1598b971 --- /dev/null +++ b/packages/react-hooks/.npmignore @@ -0,0 +1,4 @@ +**/__mocks__/** +**/__tests__/** +**/examples/** +**/tasks/** \ No newline at end of file diff --git a/packages/react-hooks/.storybook/_styles.scss b/packages/react-hooks/.storybook/_styles.scss new file mode 100644 index 000000000000..6d4469d58f2c --- /dev/null +++ b/packages/react-hooks/.storybook/_styles.scss @@ -0,0 +1,9 @@ +// +// Copyright IBM Corp. 2016, 2018 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--helpers: true; +@import '~carbon-components/scss/globals/scss/css--helpers'; diff --git a/packages/react-hooks/.storybook/addons.js b/packages/react-hooks/.storybook/addons.js new file mode 100644 index 000000000000..4c6122223a52 --- /dev/null +++ b/packages/react-hooks/.storybook/addons.js @@ -0,0 +1,9 @@ +/** + * Copyright IBM Corp. 2018, 2018 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@storybook/addon-actions/register'; +import '@storybook/addon-links/register'; diff --git a/packages/react-hooks/.storybook/config.js b/packages/react-hooks/.storybook/config.js new file mode 100644 index 000000000000..b95837b24f3e --- /dev/null +++ b/packages/react-hooks/.storybook/config.js @@ -0,0 +1,17 @@ +/** + * Copyright IBM Corp. 2018, 2018 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './_styles.scss'; +import { configure } from '@storybook/react'; + +// automatically import all files ending in *.stories.js +const req = require.context('../src', true, /-story\.js$/); +function loadStories() { + req.keys().forEach(filename => req(filename)); +} + +configure(loadStories, module); diff --git a/packages/react-hooks/.storybook/webpack.config.js b/packages/react-hooks/.storybook/webpack.config.js new file mode 100644 index 000000000000..7d4ad9b0f0aa --- /dev/null +++ b/packages/react-hooks/.storybook/webpack.config.js @@ -0,0 +1,42 @@ +/** + * Copyright IBM Corp. 2018, 2018 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +const path = require('path'); + +module.exports = ({ config, mode }) => { + config.module.rules.push({ + test: /\.s?css$/, + sideEffects: true, + use: [ + { + loader: 'style-loader', + }, + { + loader: 'css-loader', + options: { + importLoaders: 2, + }, + }, + { + loader: 'postcss-loader', + options: { + plugins: [require('autoprefixer')], + }, + }, + { + loader: 'sass-loader', + options: { + sassOptions: { + includePaths: [path.resolve(__dirname, '..', 'node_modules')], + }, + }, + }, + ], + }); + + return config; +}; diff --git a/packages/react-hooks/package.json b/packages/react-hooks/package.json new file mode 100644 index 000000000000..813eaa5912d2 --- /dev/null +++ b/packages/react-hooks/package.json @@ -0,0 +1,54 @@ +{ + "name": "@carbon/react-hooks", + "private": true, + "version": "10.0.0", + "license": "Apache-2.0", + "main": "lib/index.js", + "module": "es/index.js", + "repository": "https://github.com/carbon-design-system/carbon/tree/master/packages/react-hooks", + "bugs": "https://github.com/carbon-design-system/carbon/issues", + "keywords": [ + "ibm", + "carbon", + "carbon-design-system", + "components", + "react" + ], + "publishConfig": { + "access": "public" + }, + "scripts": { + "build": "yarn clean && rollup -c", + "clean": "rimraf es lib", + "develop": "start-storybook -p 3000", + "watch": "yarn clean && rollup -c -w" + }, + "peerDependencies": { + "react": "^16.9.0" + }, + "devDependencies": { + "@babel/core": "^7.5.5", + "@babel/preset-env": "^7.5.5", + "@babel/preset-react": "^7.0.0", + "@storybook/addon-actions": "^5.1.11", + "@storybook/addon-links": "^5.1.11", + "@storybook/addons": "^5.1.11", + "@storybook/react": "^5.1.11", + "autoprefixer": "^9.6.1", + "babel-loader": "^8.0.6", + "browserslist-config-carbon": "10.4.0", + "carbon-components": "10.6.0", + "css-loader": "^3.2.0", + "node-sass": "^4.12.0", + "postcss-loader": "^3.0.0", + "react": "^16.9.0", + "react-dom": "^16.9.0", + "rimraf": "^3.0.0", + "rollup": "^1.20.3", + "rollup-plugin-babel": "^4.3.3", + "rollup-plugin-commonjs": "^10.1.0", + "rollup-plugin-node-resolve": "^5.2.0", + "sass-loader": "^8.0.0", + "style-loader": "^1.0.0" + } +} diff --git a/packages/react-hooks/rollup.config.js b/packages/react-hooks/rollup.config.js new file mode 100644 index 000000000000..ca660df377c6 --- /dev/null +++ b/packages/react-hooks/rollup.config.js @@ -0,0 +1,55 @@ +/** + * Copyright IBM Corp. 2018, 2018 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +const resolve = require('rollup-plugin-node-resolve'); +const commonjs = require('rollup-plugin-commonjs'); +const babel = require('rollup-plugin-babel'); +const packageJson = require('./package.json'); + +const baseConfig = { + input: './src/index.js', + external: Object.keys(packageJson.peerDependencies), + plugins: [ + resolve(), + commonjs({ + include: /node_modules/, + }), + babel({ + babelrc: false, + presets: [ + [ + '@babel/preset-env', + { + targets: { + browsers: ['extends browserslist-config-carbon'], + }, + }, + ], + '@babel/preset-react', + ], + }), + ], +}; + +module.exports = [ + { + ...baseConfig, + output: { + format: 'esm', + file: 'es/index.js', + }, + }, + { + ...baseConfig, + output: { + format: 'cjs', + file: 'lib/index.js', + }, + }, +]; diff --git a/packages/react-hooks/src/__tests__/useAnnouncer-test.js b/packages/react-hooks/src/__tests__/useAnnouncer-test.js new file mode 100644 index 000000000000..624cb962c9a3 --- /dev/null +++ b/packages/react-hooks/src/__tests__/useAnnouncer-test.js @@ -0,0 +1,92 @@ +/** + * Copyright IBM Corp. 2018, 2018 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +jest.useFakeTimers(); + +describe('useAnnouncer', () => { + let React; + let act; + let render; + let cleanup; + let useAnnouncer; + + beforeEach(() => { + jest.resetModules(); + React = require('react'); + act = require('react-dom/test-utils').act; + render = require('../test-helpers').render; + cleanup = require('../test-helpers').cleanup; + useAnnouncer = require('../useAnnouncer').useAnnouncer; + }); + + afterEach(() => { + if (cleanup) { + cleanup(); + } + }); + + it('should create a live region region for each aria-live mode', () => { + function Component() { + useAnnouncer(); + return null; + } + + act(() => { + render(); + }); + + jest.runAllTimers(); + + expect(document.querySelector('[aria-live="polite"]')).toBeInstanceOf( + HTMLDivElement + ); + expect(document.querySelector('[aria-live="assertive"]')).toBeInstanceOf( + HTMLDivElement + ); + }); + + it('should update a live region for the given mode and announcement', () => { + const testMessage = 'test message'; + + function Component({ mode, message, testId }) { + const announce = useAnnouncer(); + return ( + + ); + } + + let testId = 'announce-id-1'; + act(() => { + render(); + }); + + let button = document.querySelector(`[data-test-id="${testId}"]`); + button.click(); + + jest.runAllTimers(); + + const politeRegion = document.querySelector('[aria-live="polite"]'); + expect(politeRegion.textContent).toEqual(testMessage); + + testId = 'announce-id-2'; + act(() => { + render( + + ); + }); + + button = document.querySelector(`[data-test-id="${testId}"]`); + button.click(); + + jest.runAllTimers(); + + const assertiveRegion = document.querySelector('[aria-live="assertive"]'); + expect(assertiveRegion.textContent).toEqual(testMessage); + }); +}); diff --git a/packages/react-hooks/src/__tests__/useId-test.js b/packages/react-hooks/src/__tests__/useId-test.js new file mode 100644 index 000000000000..0ad998728c82 --- /dev/null +++ b/packages/react-hooks/src/__tests__/useId-test.js @@ -0,0 +1,70 @@ +/** + * Copyright IBM Corp. 2018, 2018 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +describe('useId', () => { + let React; + let render; + let cleanup; + let useId; + + beforeEach(() => { + jest.resetModules(); + React = require('react'); + render = require('../test-helpers').render; + cleanup = require('../test-helpers').cleanup; + useId = require('../useId').useId; + }); + + afterEach(() => { + if (cleanup) { + cleanup(); + } + }); + + it('should generate a unique id for each component', () => { + function Component() { + const id = useId(); + return
; + } + + const { container } = render( + <> + + + + ); + + const ids = Array.from(container.childNodes).map(node => node.id); + const uniqueIds = new Set(ids); + expect(uniqueIds.size).toBe(2); + }); + + it('should keep the same id for each call to render', () => { + function Component() { + const id = useId(); + return
; + } + + const { container } = render(); + const id = container.childNodes[0].id; + + render(); + expect(container.childNodes[0].id).toBe(id); + }); + + it('should include a prefix in the generated `id`', () => { + const prefix = 'prefix'; + function Component() { + const id = useId(prefix); + return
; + } + + const { container } = render(); + const id = container.childNodes[0].id; + expect(id).toEqual(expect.stringContaining(prefix)); + }); +}); diff --git a/packages/react-hooks/src/__tests__/usePortalNode-test.js b/packages/react-hooks/src/__tests__/usePortalNode-test.js new file mode 100644 index 000000000000..5836fd3ee610 --- /dev/null +++ b/packages/react-hooks/src/__tests__/usePortalNode-test.js @@ -0,0 +1,89 @@ +/** + * Copyright IBM Corp. 2018, 2018 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +describe('usePortalNode', () => { + let React; + let ReactDOM; + let act; + let render; + let cleanup; + let usePortalNode; + + beforeEach(() => { + jest.resetModules(); + React = require('react'); + ReactDOM = require('react-dom'); + act = require('react-dom/test-utils').act; + render = require('../test-helpers').render; + cleanup = require('../test-helpers').cleanup; + usePortalNode = require('../usePortalNode').usePortalNode; + }); + + afterEach(() => { + if (cleanup) { + cleanup(); + } + }); + + it('should create a portal node', () => { + const testId = 'test-id'; + let portalNode; + function Component() { + portalNode = usePortalNode(); + return ( + <> + Component + {portalNode && + ReactDOM.createPortal(
, portalNode)} + + ); + } + + act(() => { + render(); + }); + + expect(portalNode).toBeDefined(); + // The portal node should exist in document.body + const children = Array.from(document.body.childNodes); + expect(children.indexOf(portalNode)).not.toBe(-1); + + // The portal node should have rendered a node with our `data-test-id` + expect( + document.body.querySelector(`[data-test-id="${testId}"]`) + ).toBeDefined(); + }); + + it('should create a new node when given an id', () => { + const id = 'test-id'; + function Component() { + usePortalNode(id); + return null; + } + + act(() => { + render(); + }); + + expect(document.body.querySelector(id)).toBeDefined(); + }); + + it('should reuse an existing node with a given id', () => { + const id = 'test-id'; + function Component() { + usePortalNode(id); + return null; + } + + act(() => { + const { rerender } = render(); + rerender(); + }); + + expect(document.body.querySelectorAll(`#${id}`).length).toBe(1); + }); +}); diff --git a/packages/react-hooks/src/index.js b/packages/react-hooks/src/index.js new file mode 100644 index 000000000000..8debd14a43d1 --- /dev/null +++ b/packages/react-hooks/src/index.js @@ -0,0 +1,10 @@ +/** + * Copyright IBM Corp. 2018, 2018 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +export * from './useAnnouncer'; +export * from './useId'; +export * from './usePortalNode'; diff --git a/packages/react-hooks/src/test-helpers.js b/packages/react-hooks/src/test-helpers.js new file mode 100644 index 000000000000..f2c8565c8b14 --- /dev/null +++ b/packages/react-hooks/src/test-helpers.js @@ -0,0 +1,33 @@ +/** + * Copyright IBM Corp. 2018, 2018 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import ReactDOM from 'react-dom'; + +const containers = new Set(); + +export function render( + element, + { container = document.createElement('div') } = {} +) { + containers.add(container); + document.body.appendChild(container); + ReactDOM.render(element, container); + return { + container, + rerender() { + ReactDOM.render(element, container); + }, + }; +} + +export function cleanup() { + for (const node of containers) { + ReactDOM.unmountComponentAtNode(node); + node.parentNode.removeChild(node); + containers.delete(node); + } +} diff --git a/packages/react-hooks/src/useAnnouncer-story.js b/packages/react-hooks/src/useAnnouncer-story.js new file mode 100644 index 000000000000..9bceec679772 --- /dev/null +++ b/packages/react-hooks/src/useAnnouncer-story.js @@ -0,0 +1,109 @@ +/** + * Copyright IBM Corp. 2018, 2018 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { storiesOf } from '@storybook/react'; +import React, { useState } from 'react'; +import { useAnnouncer, usePoliteAnnouncer, useAssertiveAnnouncer } from './'; + +storiesOf('useAnnouncer', module) + .add('default', () => { + function DemoComponent() { + const [mode, updateMode] = useState('polite'); + const [announcement, updateAnnouncement] = useState('test message'); + const announce = useAnnouncer(); + + function onModeChange(event) { + updateMode(event.target.value); + } + + function onAnnouncementChange(event) { + updateAnnouncement(event.target.value); + } + + return ( + <> +
+ + +
+
+ + +
+ + + ); + } + return ; + }) + .add('polite announcer', () => { + function DemoComponent() { + const announce = usePoliteAnnouncer(); + const [count, setCount] = useState(1); + function onClick() { + setCount(count + 1); + announce(`Polite message ${count}`); + } + return ; + } + return ; + }) + .add('assertive announcer', () => { + function DemoComponent() { + const announce = useAssertiveAnnouncer(); + const [count, setCount] = useState(1); + function onClick() { + setCount(count + 1); + announce(`Assertive message ${count}`); + } + return ; + } + return ; + }) + .add('multiple announcers', () => { + function DemoComponent() { + return ( + <> + + + + ); + } + + function Assertive() { + const announce = useAnnouncer(); + const [count, setCount] = useState(1); + function onClick() { + setCount(count + 1); + announce('assertive', `Assertive message ${count}`); + } + return ; + } + + function Polite() { + const announce = useAnnouncer(); + const [count, setCount] = useState(1); + function onClick() { + setCount(count + 1); + announce('polite', `Polite message ${count}`); + } + return ; + } + + return ; + }); diff --git a/packages/react-hooks/src/useAnnouncer.js b/packages/react-hooks/src/useAnnouncer.js new file mode 100644 index 000000000000..6f6a1b46f94d --- /dev/null +++ b/packages/react-hooks/src/useAnnouncer.js @@ -0,0 +1,100 @@ +/** + * Copyright IBM Corp. 2018, 2018 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { useEffect, useState } from 'react'; +import { usePortalNode } from './usePortalNode'; + +/** + * Provides an `announce` method that allows a user to queue up an assertive or + * polite message to the user. This message is displayed in an `aria-live` + * region with the appropriate mode and the message is set as its text content. + * This `aria-live` region is the same for all components, so ordering of + * messages sent is important. + */ +export function useAnnouncer() { + const node = usePortalNode('carbon-announcer'); + const [mode, updateMode] = useState('polite'); + const [announcement, updateAnnouncement] = useState(''); + + function announce(mode, message) { + updateMode(mode); + updateAnnouncement(message); + } + + useEffect(() => { + if (!node) { + return; + } + + if (!node.classList.contains('bx--visually-hidden')) { + node.classList.add('bx--visually-hidden'); + } + + // In this effect, we'll need to setup the `#carbon-announcer` node with two + // corresponding announcement nodes if they do not exist already. If they + // already exist, then we can reuse them. + let assertiveNode = node.querySelector('#carbon-assertive-announcement'); + if (!assertiveNode) { + assertiveNode = document.createElement('div'); + assertiveNode.id = 'carbon-assertive-announcement'; + assertiveNode.setAttribute('aria-live', 'assertive'); + node.appendChild(assertiveNode); + } + + let politeNode = node.querySelector('#carbon-polite-announcement'); + if (!politeNode) { + politeNode = document.createElement('div'); + politeNode.id = 'carbon-polite-announcement'; + politeNode.setAttribute('aria-live', 'polite'); + node.appendChild(politeNode); + } + }, [node]); + + useEffect(() => { + if (!node) { + return; + } + + // Each time the mode or announcement changes, we'll want to update the + // message at that node. + const assertiveNode = node.querySelector('#carbon-assertive-announcement'); + const politeNode = node.querySelector('#carbon-polite-announcement'); + const timeoutId = setTimeout(() => { + if (mode === 'assertive' && assertiveNode.textContent !== announcement) { + assertiveNode.textContent = announcement; + } + + if (mode === 'polite' && politeNode.textContent !== announcement) { + politeNode.textContent = announcement; + } + }, 300); + + return () => { + window.clearTimeout(timeoutId); + }; + }, [node, mode, announcement]); + + return announce; +} + +/** + * Provides an announce method that will allow the user to queue up messages in + * an `aria-live="assertive"` region + */ +export function useAssertiveAnnouncer() { + const announce = useAnnouncer(); + return message => announce('assertive', message); +} + +/** + * Provides an announce method that will allow the user to queue up messages in + * an `aria-live="polite"` region + */ +export function usePoliteAnnouncer() { + const announce = useAnnouncer(); + return message => announce('polite', message); +} diff --git a/packages/react-hooks/src/useId-story.js b/packages/react-hooks/src/useId-story.js new file mode 100644 index 000000000000..95a01b8eaa61 --- /dev/null +++ b/packages/react-hooks/src/useId-story.js @@ -0,0 +1,46 @@ +/** + * Copyright IBM Corp. 2018, 2018 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { storiesOf } from '@storybook/react'; +import React from 'react'; +import { useId } from './'; + +storiesOf('useId', module) + .add('default', () => { + function DemoComponent() { + const id = useId(); + return ( +
+ This node has an id of {id} +
+ ); + } + return ; + }) + .add('with prefix', () => { + function List({ children }) { + const id = useId('list'); + return
    {children}
; + } + + function ListItem() { + const id = useId('list-item'); + return ( +
  • + List item {id} +
  • + ); + } + + return ( + + + + + + ); + }); diff --git a/packages/react-hooks/src/useId.js b/packages/react-hooks/src/useId.js new file mode 100644 index 000000000000..798225611440 --- /dev/null +++ b/packages/react-hooks/src/useId.js @@ -0,0 +1,38 @@ +/** + * Copyright IBM Corp. 2018, 2018 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { useRef } from 'react'; + +let id = 0; + +/** + * Provides a unique identifier with an optional prefix, useful for dynamically + * creating `id` values for controls, especially alongside `aria-labelledby` or + * `htmlFor`. This `id` value is guaranteed to be the same for the duration of + * the component. + * + * @example + * function TextInput() { + * const id = useId('text-input'); + * return ( + *
    + * + * + *
    + * ); + * } + * + * @param {string?} prefix + * @returns {string} + */ +export function useId(prefix) { + const ref = useRef(++id); + if (prefix) { + return `${prefix}-${ref.current}`; + } + return '' + ref.current; +} diff --git a/packages/react-hooks/src/usePortalNode-story.js b/packages/react-hooks/src/usePortalNode-story.js new file mode 100644 index 000000000000..41efc7204dc5 --- /dev/null +++ b/packages/react-hooks/src/usePortalNode-story.js @@ -0,0 +1,37 @@ +/** + * Copyright IBM Corp. 2018, 2018 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { storiesOf } from '@storybook/react'; +import React from 'react'; +import { createPortal } from 'react-dom'; +import { usePortalNode } from './'; + +storiesOf('usePortalNode', module) + .add('default', () => { + function DemoComponent() { + const node = usePortalNode(); + return node && createPortal('Inside a portal!', node); + } + + return ; + }) + .add('with id', () => { + function DemoComponent() { + const node = usePortalNode('portal-root'); + return ( + node && + createPortal( + <> + Inside a portal with id #portal-root + , + node + ) + ); + } + + return ; + }); diff --git a/packages/react-hooks/src/usePortalNode.js b/packages/react-hooks/src/usePortalNode.js new file mode 100644 index 000000000000..1570372f7382 --- /dev/null +++ b/packages/react-hooks/src/usePortalNode.js @@ -0,0 +1,73 @@ +/** + * Copyright IBM Corp. 2018, 2018 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { useEffect, useState } from 'react'; + +/** + * @param {string?} id + */ +export function usePortalNode(id) { + const [portalNode, setPortalNode] = useState(null); + + useEffect(() => { + const [node, cleanup] = findOrCreateRoot(id); + setPortalNode(node); + + return () => { + cleanup(); + setPortalNode(null); + }; + }, [id]); + + return portalNode; +} + +const activePortals = new Map(); + +function findOrCreateRoot(id) { + const node = findOrCreateNode(id); + if (!id) { + // eslint-disable-next-line no-inner-declarations + function cleanup() { + document.body.removeChild(node); + } + return [node, cleanup]; + } + + const currentPortalCount = activePortals.get(id) || 0; + activePortals.set(id, currentPortalCount + 1); + + function cleanup() { + const currentPortalCount = activePortals.get(id); + if (currentPortalCount === 1) { + document.body.removeChild(node); + activePortals.delete(id); + } else { + activePortals.set(id, currentPortalCount - 1); + } + } + + return [node, cleanup]; +} + +function findOrCreateNode(id) { + if (!id) { + const node = document.createElement('div'); + document.body.appendChild(node); + return node; + } + + const existingNode = document.getElementById(id); + if (existingNode) { + return existingNode; + } + + const node = document.createElement('div'); + node.id = id; + document.body.appendChild(node); + return node; +} diff --git a/yarn.lock b/yarn.lock index 344073d2f1b4..62d0c0ef3b1a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -102,6 +102,26 @@ semver "^5.4.1" source-map "^0.5.0" +"@babel/core@^7.5.5": + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.5.5.tgz#17b2686ef0d6bc58f963dddd68ab669755582c30" + integrity sha512-i4qoSr2KTtce0DmkuuQBV4AuQgGPUcPXMr9L5MyYAtk06z068lQ10a4O009fe5OB/DfNV+h+qqT7ddNV8UnRjg== + dependencies: + "@babel/code-frame" "^7.5.5" + "@babel/generator" "^7.5.5" + "@babel/helpers" "^7.5.5" + "@babel/parser" "^7.5.5" + "@babel/template" "^7.4.4" + "@babel/traverse" "^7.5.5" + "@babel/types" "^7.5.5" + convert-source-map "^1.1.0" + debug "^4.1.0" + json5 "^2.1.0" + lodash "^4.17.13" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + "@babel/generator@^7.4.0", "@babel/generator@^7.5.0": version "7.5.0" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.5.0.tgz#f20e4b7a91750ee8b63656073d843d2a736dca4a" @@ -177,6 +197,15 @@ "@babel/types" "^7.4.4" lodash "^4.17.11" +"@babel/helper-define-map@^7.5.5": + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.5.5.tgz#3dec32c2046f37e09b28c93eb0b103fd2a25d369" + integrity sha512-fTfxx7i0B5NJqvUOBBGREnrqbTxRh7zinBANpZXAVDlsZxYdclDp467G1sQ8VZYMnAURY3RpBUAgOYT9GfzHBg== + dependencies: + "@babel/helper-function-name" "^7.1.0" + "@babel/types" "^7.5.5" + lodash "^4.17.13" + "@babel/helper-explode-assignable-expression@^7.1.0": version "7.1.0" resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz#537fa13f6f1674df745b0c00ec8fe4e99681c8f6" @@ -215,6 +244,13 @@ dependencies: "@babel/types" "^7.0.0" +"@babel/helper-member-expression-to-functions@^7.5.5": + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.5.5.tgz#1fb5b8ec4453a93c439ee9fe3aeea4a84b76b590" + integrity sha512-5qZ3D1uMclSNqYcXqiHoA0meVdv+xUEex9em2fqMnrk/scphGlGgg66zjMrPJESPwrFJ6sbfFQYUSa0Mz7FabA== + dependencies: + "@babel/types" "^7.5.5" + "@babel/helper-module-imports@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz#96081b7111e486da4d2cd971ad1a4fe216cc2e3d" @@ -274,6 +310,16 @@ "@babel/traverse" "^7.4.4" "@babel/types" "^7.4.4" +"@babel/helper-replace-supers@^7.5.5": + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.5.5.tgz#f84ce43df031222d2bad068d2626cb5799c34bc2" + integrity sha512-XvRFWrNnlsow2u7jXDuH4jDDctkxbS7gXssrP4q2nUD606ukXHRvydj346wmNg+zAgpFx4MWf4+usfC93bElJg== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.5.5" + "@babel/helper-optimise-call-expression" "^7.0.0" + "@babel/traverse" "^7.5.5" + "@babel/types" "^7.5.5" + "@babel/helper-simple-access@^7.1.0": version "7.1.0" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz#65eeb954c8c245beaa4e859da6188f39d71e585c" @@ -299,7 +345,7 @@ "@babel/traverse" "^7.1.0" "@babel/types" "^7.2.0" -"@babel/helpers@^7.4.3", "@babel/helpers@^7.5.0": +"@babel/helpers@^7.4.3", "@babel/helpers@^7.5.0", "@babel/helpers@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.5.5.tgz#63908d2a73942229d1e6685bc2a0e730dde3b75e" integrity sha512-nRq2BUhxZFnfEn/ciJuhklHvFOqjJUD5wpx+1bxUF2axL9C+v4DE/dmp5sT2dKnpOs4orZWzpAZqlCy8QqE/7g== @@ -413,7 +459,7 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-object-rest-spread" "^7.2.0" -"@babel/plugin-proposal-object-rest-spread@^7.0.0", "@babel/plugin-proposal-object-rest-spread@^7.3.2", "@babel/plugin-proposal-object-rest-spread@^7.4.3", "@babel/plugin-proposal-object-rest-spread@^7.5.0", "@babel/plugin-proposal-object-rest-spread@^7.5.2": +"@babel/plugin-proposal-object-rest-spread@^7.0.0", "@babel/plugin-proposal-object-rest-spread@^7.3.2", "@babel/plugin-proposal-object-rest-spread@^7.4.3", "@babel/plugin-proposal-object-rest-spread@^7.5.0", "@babel/plugin-proposal-object-rest-spread@^7.5.2", "@babel/plugin-proposal-object-rest-spread@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.5.5.tgz#61939744f71ba76a3ae46b5eea18a54c16d22e58" integrity sha512-F2DxJJSQ7f64FyTVl5cw/9MWn6naXGdk3Q3UhDbFEEHv+EilCPoeRD3Zh/Utx1CJz4uyKlQ4uH+bJPbEhMV7Zw== @@ -553,6 +599,14 @@ "@babel/helper-plugin-utils" "^7.0.0" lodash "^4.17.11" +"@babel/plugin-transform-block-scoping@^7.5.5": + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.5.5.tgz#a35f395e5402822f10d2119f6f8e045e3639a2ce" + integrity sha512-82A3CLRRdYubkG85lKwhZB0WZoHxLGsJdux/cOVaJCJpvYFl1LVzAIFyRsa7CvXqW8rBM4Zf3Bfn8PHt5DP0Sg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + lodash "^4.17.13" + "@babel/plugin-transform-classes@7.4.3": version "7.4.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.4.3.tgz#adc7a1137ab4287a555d429cc56ecde8f40c062c" @@ -581,6 +635,20 @@ "@babel/helper-split-export-declaration" "^7.4.4" globals "^11.1.0" +"@babel/plugin-transform-classes@^7.5.5": + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.5.5.tgz#d094299d9bd680a14a2a0edae38305ad60fb4de9" + integrity sha512-U2htCNK/6e9K7jGyJ++1p5XRU+LJjrwtoiVn9SzRlDT2KubcZ11OOwy3s24TjHxPgxNwonCYP7U2K51uVYCMDg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.0.0" + "@babel/helper-define-map" "^7.5.5" + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-optimise-call-expression" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-replace-supers" "^7.5.5" + "@babel/helper-split-export-declaration" "^7.4.4" + globals "^11.1.0" + "@babel/plugin-transform-computed-properties@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz#83a7df6a658865b1c8f641d510c6f3af220216da" @@ -736,6 +804,14 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-replace-supers" "^7.1.0" +"@babel/plugin-transform-object-super@^7.5.5": + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.5.5.tgz#c70021df834073c65eb613b8679cc4a381d1a9f9" + integrity sha512-un1zJQAhSosGFBduPgN/YFNvWVpRuHKU7IHBglLoLZsGmruJPOo6pbInneflUdmq7YvSVqhpPs5zdBvLnteltQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-replace-supers" "^7.5.5" + "@babel/plugin-transform-parameters@^7.4.3", "@babel/plugin-transform-parameters@^7.4.4": version "7.4.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.4.4.tgz#7556cf03f318bd2719fe4c922d2d808be5571e16" @@ -1007,6 +1083,62 @@ js-levenshtein "^1.1.3" semver "^5.5.0" +"@babel/preset-env@^7.5.5": + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.5.5.tgz#bc470b53acaa48df4b8db24a570d6da1fef53c9a" + integrity sha512-GMZQka/+INwsMz1A5UEql8tG015h5j/qjptpKY2gJ7giy8ohzU710YciJB5rcKsWGWHiW3RUnHib0E5/m3Tp3A== + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-async-generator-functions" "^7.2.0" + "@babel/plugin-proposal-dynamic-import" "^7.5.0" + "@babel/plugin-proposal-json-strings" "^7.2.0" + "@babel/plugin-proposal-object-rest-spread" "^7.5.5" + "@babel/plugin-proposal-optional-catch-binding" "^7.2.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" + "@babel/plugin-syntax-async-generators" "^7.2.0" + "@babel/plugin-syntax-dynamic-import" "^7.2.0" + "@babel/plugin-syntax-json-strings" "^7.2.0" + "@babel/plugin-syntax-object-rest-spread" "^7.2.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.2.0" + "@babel/plugin-transform-arrow-functions" "^7.2.0" + "@babel/plugin-transform-async-to-generator" "^7.5.0" + "@babel/plugin-transform-block-scoped-functions" "^7.2.0" + "@babel/plugin-transform-block-scoping" "^7.5.5" + "@babel/plugin-transform-classes" "^7.5.5" + "@babel/plugin-transform-computed-properties" "^7.2.0" + "@babel/plugin-transform-destructuring" "^7.5.0" + "@babel/plugin-transform-dotall-regex" "^7.4.4" + "@babel/plugin-transform-duplicate-keys" "^7.5.0" + "@babel/plugin-transform-exponentiation-operator" "^7.2.0" + "@babel/plugin-transform-for-of" "^7.4.4" + "@babel/plugin-transform-function-name" "^7.4.4" + "@babel/plugin-transform-literals" "^7.2.0" + "@babel/plugin-transform-member-expression-literals" "^7.2.0" + "@babel/plugin-transform-modules-amd" "^7.5.0" + "@babel/plugin-transform-modules-commonjs" "^7.5.0" + "@babel/plugin-transform-modules-systemjs" "^7.5.0" + "@babel/plugin-transform-modules-umd" "^7.2.0" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.4.5" + "@babel/plugin-transform-new-target" "^7.4.4" + "@babel/plugin-transform-object-super" "^7.5.5" + "@babel/plugin-transform-parameters" "^7.4.4" + "@babel/plugin-transform-property-literals" "^7.2.0" + "@babel/plugin-transform-regenerator" "^7.4.5" + "@babel/plugin-transform-reserved-words" "^7.2.0" + "@babel/plugin-transform-shorthand-properties" "^7.2.0" + "@babel/plugin-transform-spread" "^7.2.0" + "@babel/plugin-transform-sticky-regex" "^7.2.0" + "@babel/plugin-transform-template-literals" "^7.4.4" + "@babel/plugin-transform-typeof-symbol" "^7.2.0" + "@babel/plugin-transform-unicode-regex" "^7.4.4" + "@babel/types" "^7.5.5" + browserslist "^4.6.0" + core-js-compat "^3.1.1" + invariant "^2.2.2" + js-levenshtein "^1.1.3" + semver "^5.5.0" + "@babel/preset-flow@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/preset-flow/-/preset-flow-7.0.0.tgz#afd764835d9535ec63d8c7d4caf1c06457263da2" @@ -3253,6 +3385,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-12.0.12.tgz#cc791b402360db1eaf7176479072f91ee6c6c7ca" integrity sha512-Uy0PN4R5vgBUXFoJrKryf5aTk3kJ8Rv3PdlHjl6UaX+Cqp1QE0yPQ68MPXGrZOfG7gZVNDIJZYyot0B9ubXUrQ== +"@types/node@^12.7.2": + version "12.7.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.7.3.tgz#27b3f40addaf2f580459fdb405222685542f907a" + integrity sha512-3SiLAIBkDWDg6vFo0+5YJyHPWU9uwu40Qe+v+0MH8wRKYBimHvvAOyk3EzMrD/TrIlLYfXrqDqrg913PynrMJQ== + "@types/normalize-package-data@^2.4.0": version "2.4.0" resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" @@ -3539,6 +3676,11 @@ acorn@^6.0.1, acorn@^6.0.5, acorn@^6.0.7, acorn@^6.1.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.2.0.tgz#67f0da2fc339d6cfb5d6fb244fd449f33cd8bbe3" integrity sha512-8oe72N3WPMjA+2zVG71Ia0nXZ8DpQH+QyyHO+p06jT8eg8FGG3FbcUIi8KziHlAfheJQZeoqbvq1mQSQHXKYLw== +acorn@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.0.0.tgz#26b8d1cd9a9b700350b71c0905546f64d1284e7a" + integrity sha512-PaF/MduxijYYt7unVGRuds1vBC9bFxbNf+VWqhOClfdgy7RlVkQqt610ig1/yxTgsDIfW1cWDel5EBbOy3jdtQ== + adaro@1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/adaro/-/adaro-1.0.4.tgz#05706a054d4d0097ce1c3ea319281b85c9dd8a24" @@ -3643,6 +3785,11 @@ ajv-keywords@^3.1.0: resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.0.tgz#4b831e7b531415a7cc518cd404e73f6193c6349d" integrity sha512-aUjdRFISbuFOl0EIZc+9e4FfZp0bDZgAdOOf30bJmw8VM9v84SHyVyxDfbWxpGYbdZD/9XoKxfHVNmxPkhwyGw== +ajv-keywords@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.1.tgz#ef916e271c64ac12171fd8384eaae6b2345854da" + integrity sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ== + ajv@^4.7.0: version "4.11.8" resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" @@ -3661,6 +3808,16 @@ ajv@^6.1.0, ajv@^6.10.0, ajv@^6.5.5, ajv@^6.9.1: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@^6.10.2: + version "6.10.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" + integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw== + dependencies: + fast-deep-equal "^2.0.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + all-contributors-cli@^5.2.1: version "5.11.0" resolved "https://registry.yarnpkg.com/all-contributors-cli/-/all-contributors-cli-5.11.0.tgz#5fc022b8064ee09e4370dc5e9d92d59c7ee0bbf3" @@ -4467,6 +4624,19 @@ autoprefixer@^9.0.0, autoprefixer@^9.4.3, autoprefixer@^9.4.9, autoprefixer@^9.5 postcss "^7.0.16" postcss-value-parser "^3.3.1" +autoprefixer@^9.6.1: + version "9.6.1" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.6.1.tgz#51967a02d2d2300bb01866c1611ec8348d355a47" + integrity sha512-aVo5WxR3VyvyJxcJC3h4FKfwCQvQWb1tSI5VHNibddCVWrcD1NvlxEweg3TSgiPztMnWfjpy2FURKA2kvDE+Tw== + dependencies: + browserslist "^4.6.3" + caniuse-lite "^1.0.30000980" + chalk "^2.4.2" + normalize-range "^0.1.2" + num2fraction "^1.2.2" + postcss "^7.0.17" + postcss-value-parser "^4.0.0" + aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" @@ -4602,7 +4772,7 @@ babel-jest@^24.8.0: chalk "^2.4.2" slash "^2.0.0" -babel-loader@^8.0.0, babel-loader@^8.0.4, babel-loader@^8.0.5: +babel-loader@^8.0.0, babel-loader@^8.0.4, babel-loader@^8.0.5, babel-loader@^8.0.6: version "8.0.6" resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.0.6.tgz#e33bdb6f362b03f4bb141a0c21ab87c501b70dfb" integrity sha512-4BmWKtBOBm13uoUwd08UwjZlaw3O9GWf456R9j+5YykFZ6LUIjIKLc0zEZf+hauxPOJs96C8k6FvYD09vWzhYw== @@ -5504,6 +5674,15 @@ browserslist@^4.0.0, browserslist@^4.5.2, browserslist@^4.6.0, browserslist@^4.6 electron-to-chromium "^1.3.164" node-releases "^1.1.23" +browserslist@^4.6.3: + version "4.7.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.7.0.tgz#9ee89225ffc07db03409f2fee524dc8227458a17" + integrity sha512-9rGNDtnj+HaahxiVV38Gn8n8Lr8REKsel68v1sPFfIGEK6uSXTY3h9acgiT1dZVtOOUtifo/Dn8daDQ5dUgVsA== + dependencies: + caniuse-lite "^1.0.30000989" + electron-to-chromium "^1.3.247" + node-releases "^1.1.29" + bs-recipes@1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/bs-recipes/-/bs-recipes-1.3.4.tgz#0d2d4d48a718c8c044769fdc4f89592dc8b69585" @@ -5776,6 +5955,11 @@ caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30000864, can resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000979.tgz#92f16d00186a6cf20d6c5711bb6e042a3d667029" integrity sha512-gcu45yfq3B7Y+WB05fOMfr0EiSlq+1u+m6rPHyJli/Wy3PVQNGaU7VA4bZE5qw+AU2UVOBR/N5g1bzADUqdvFw== +caniuse-lite@^1.0.30000980, caniuse-lite@^1.0.30000989: + version "1.0.30000989" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000989.tgz#b9193e293ccf7e4426c5245134b8f2a56c0ac4b9" + integrity sha512-vrMcvSuMz16YY6GSVZ0dWDTJP8jqk3iFQ/Aq5iqblPwxSVVZI+zxDyTX0VPqtQsDnfdrBDcsmhgTEOh5R8Lbpw== + capture-exit@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" @@ -6284,6 +6468,15 @@ clone-deep@^2.0.1: kind-of "^6.0.0" shallow-clone "^1.0.0" +clone-deep@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" + integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== + dependencies: + is-plain-object "^2.0.4" + kind-of "^6.0.2" + shallow-clone "^3.0.0" + clone-regexp@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/clone-regexp/-/clone-regexp-1.0.1.tgz#051805cd33173375d82118fc0918606da39fd60f" @@ -7137,6 +7330,24 @@ css-loader@^2.1.1: postcss-value-parser "^3.3.0" schema-utils "^1.0.0" +css-loader@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-3.2.0.tgz#bb570d89c194f763627fcf1f80059c6832d009b2" + integrity sha512-QTF3Ud5H7DaZotgdcJjGMvyDj5F3Pn1j/sC6VBEOVp94cbwqyIBdcs/quzj4MC1BKQSrTpQznegH/5giYbhnCQ== + dependencies: + camelcase "^5.3.1" + cssesc "^3.0.0" + icss-utils "^4.1.1" + loader-utils "^1.2.3" + normalize-path "^3.0.0" + postcss "^7.0.17" + postcss-modules-extract-imports "^2.0.0" + postcss-modules-local-by-default "^3.0.2" + postcss-modules-scope "^2.1.0" + postcss-modules-values "^3.0.0" + postcss-value-parser "^4.0.0" + schema-utils "^2.0.0" + css-select-base-adapter@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7" @@ -8090,6 +8301,11 @@ electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.122, electron-to-chromium resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.186.tgz#17d87e7661121724ea4c81c9960c3f26a5228c0c" integrity sha512-lRyyEUDKenKv/EBVFgfDZDYTDdoAZhzuE+inMUP79+22NDPAA2Ox+f3AShILIjPoUIqRGwvPNbzFcyU8km8g4A== +electron-to-chromium@^1.3.247: + version "1.3.250" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.250.tgz#1f383c16aeb75e7bddbd6a0491237eca81b2cb1f" + integrity sha512-2OAU91iUw83QvzuWJPfT+FMj+O+DC1EyTx1QBFcc9WZzOQSfZEAWINpdLWElxkgfiqTvQRDOKg0DkMZd9QoNug== + elegant-spinner@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e" @@ -11128,7 +11344,7 @@ icss-utils@^2.1.0: dependencies: postcss "^6.0.1" -icss-utils@^4.1.0: +icss-utils@^4.0.0, icss-utils@^4.1.0, icss-utils@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.1.tgz#21170b53789ee27447c2f47dd683081403f9a467" integrity sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA== @@ -11937,6 +12153,13 @@ is-redirect@^1.0.0: resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" integrity sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ= +is-reference@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.1.3.tgz#e99059204b66fdbe09305cfca715a29caa5c8a51" + integrity sha512-W1iHHv/oyBb2pPxkBxtaewxa1BC58Pn5J0hogyCdefwUIvb6R+TGbAcIa4qPNYLqLhb3EnOgUf2MQkkF76BcKw== + dependencies: + "@types/estree" "0.0.39" + is-regex@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" @@ -14802,7 +15025,7 @@ negotiator@0.6.2: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== -neo-async@^2.5.0, neo-async@^2.6.0: +neo-async@^2.5.0, neo-async@^2.6.0, neo-async@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw== @@ -14985,6 +15208,13 @@ node-releases@^1.1.13, node-releases@^1.1.23: dependencies: semver "^5.3.0" +node-releases@^1.1.29: + version "1.1.29" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.29.tgz#86a57c6587a30ecd6726449e5d293466b0a0bb86" + integrity sha512-R5bDhzh6I+tpi/9i2hrrvGJ3yKPYzlVOORDkXhnZuwi5D3q1I5w4vYy24PJXTcLk9Q0kws9TO77T75bcK8/ysQ== + dependencies: + semver "^5.3.0" + node-sass@4.10.0: version "4.10.0" resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.10.0.tgz#dcc2b364c0913630945ccbf7a2bbf1f926effca4" @@ -15032,7 +15262,7 @@ node-sass@^3.1.2: request "^2.61.0" sass-graph "^2.1.1" -node-sass@^4.11.0, node-sass@^4.8.3, node-sass@^4.9.4: +node-sass@^4.11.0, node-sass@^4.12.0, node-sass@^4.8.3, node-sass@^4.9.4: version "4.12.0" resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.12.0.tgz#0914f531932380114a30cc5fa4fa63233a25f017" integrity sha512-A1Iv4oN+Iel6EPv77/HddXErL2a+gZ4uBeZUy+a8O35CFYTXhgA8MgLCWBtwpGZdCvTvQ9d+bQxX/QC36GDPpQ== @@ -16593,6 +16823,16 @@ postcss-modules-local-by-default@^2.0.6: postcss-selector-parser "^6.0.0" postcss-value-parser "^3.3.1" +postcss-modules-local-by-default@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.2.tgz#e8a6561be914aaf3c052876377524ca90dbb7915" + integrity sha512-jM/V8eqM4oJ/22j0gx4jrp63GSvDH6v86OqyTHHUvk4/k1vceipZsaymiZ5PvocqZOl5SFHiFJqjs3la0wnfIQ== + dependencies: + icss-utils "^4.1.1" + postcss "^7.0.16" + postcss-selector-parser "^6.0.2" + postcss-value-parser "^4.0.0" + postcss-modules-scope@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz#d6ea64994c79f97b62a72b426fbe6056a194bb90" @@ -16625,6 +16865,14 @@ postcss-modules-values@^2.0.0: icss-replace-symbols "^1.1.0" postcss "^7.0.6" +postcss-modules-values@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz#5b5000d6ebae29b4255301b4a3a54574423e7f10" + integrity sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg== + dependencies: + icss-utils "^4.0.0" + postcss "^7.0.6" + postcss-normalize-charset@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz#ef9ee71212d7fe759c78ed162f61ed62b5cb93f1" @@ -17549,6 +17797,16 @@ react-dom@^16.6.0, react-dom@^16.8.3, react-dom@^16.8.6: prop-types "^15.6.2" scheduler "^0.13.6" +react-dom@^16.9.0: + version "16.9.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.9.0.tgz#5e65527a5e26f22ae3701131bcccaee9fb0d3962" + integrity sha512-YFT2rxO9hM70ewk9jq0y6sQk8cL02xm4+IzYBz75CQGlClQQ1Bxq0nhHF6OtSbit+AIahujJgb/CPRibFkMNJQ== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.2" + scheduler "^0.15.0" + react-draggable@^3.1.1: version "3.3.0" resolved "https://registry.yarnpkg.com/react-draggable/-/react-draggable-3.3.0.tgz#2ed7ea3f92e7d742d747f9e6324860606cd4d997" @@ -17764,6 +18022,15 @@ react@^16.6.0, react@^16.8.3, react@^16.8.6: prop-types "^15.6.2" scheduler "^0.13.6" +react@^16.9.0: + version "16.9.0" + resolved "https://registry.yarnpkg.com/react/-/react-16.9.0.tgz#40ba2f9af13bc1a38d75dbf2f4359a5185c4f7aa" + integrity sha512-+7LQnFBwkiw+BobzOF6N//BdoNw0ouwmSJTEm9cglOOmsg/TMiFHZLe2sEoN5M7LgJTj9oHH0gxklfnQe66S1w== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.2" + reactcss@^1.2.0: version "1.2.3" resolved "https://registry.yarnpkg.com/reactcss/-/reactcss-1.2.3.tgz#c00013875e557b1cf0dfd9a368a1c3dab3b548dd" @@ -18567,6 +18834,13 @@ resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.10.1, resolve@^1.11. dependencies: path-parse "^1.0.6" +resolve@^1.11.1: + version "1.12.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.12.0.tgz#3fc644a35c84a48554609ff26ec52b66fa577df6" + integrity sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w== + dependencies: + path-parse "^1.0.6" + resp-modifier@6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/resp-modifier/-/resp-modifier-6.0.2.tgz#b124de5c4fbafcba541f48ffa73970f4aa456b4f" @@ -18650,7 +18924,7 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^3.0.0" inherits "^2.0.1" -rollup-plugin-babel@^4.0.0, rollup-plugin-babel@^4.0.3, rollup-plugin-babel@^4.3.2: +rollup-plugin-babel@^4.0.0, rollup-plugin-babel@^4.0.3, rollup-plugin-babel@^4.3.2, rollup-plugin-babel@^4.3.3: version "4.3.3" resolved "https://registry.yarnpkg.com/rollup-plugin-babel/-/rollup-plugin-babel-4.3.3.tgz#7eb5ac16d9b5831c3fd5d97e8df77ba25c72a2aa" integrity sha512-tKzWOCmIJD/6aKNz0H1GMM+lW1q9KyFubbWzGiOG540zxPPifnEAHTZwjo0g991Y+DyOZcLqBgqOdqazYE5fkw== @@ -18658,6 +18932,17 @@ rollup-plugin-babel@^4.0.0, rollup-plugin-babel@^4.0.3, rollup-plugin-babel@^4.3 "@babel/helper-module-imports" "^7.0.0" rollup-pluginutils "^2.8.1" +rollup-plugin-commonjs@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/rollup-plugin-commonjs/-/rollup-plugin-commonjs-10.1.0.tgz#417af3b54503878e084d127adf4d1caf8beb86fb" + integrity sha512-jlXbjZSQg8EIeAAvepNwhJj++qJWNJw1Cl0YnOqKtP5Djx+fFGkp3WRh+W0ASCaFG5w1jhmzDxgu3SJuVxPF4Q== + dependencies: + estree-walker "^0.6.1" + is-reference "^1.1.2" + magic-string "^0.25.2" + resolve "^1.11.0" + rollup-pluginutils "^2.8.1" + rollup-plugin-commonjs@^9.0.0, rollup-plugin-commonjs@^9.2.0, rollup-plugin-commonjs@^9.3.4: version "9.3.4" resolved "https://registry.yarnpkg.com/rollup-plugin-commonjs/-/rollup-plugin-commonjs-9.3.4.tgz#2b3dddbbbded83d45c36ff101cdd29e924fd23bc" @@ -18700,6 +18985,17 @@ rollup-plugin-node-resolve@^4.0.0, rollup-plugin-node-resolve@^4.2.3: is-module "^1.0.0" resolve "^1.10.0" +rollup-plugin-node-resolve@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz#730f93d10ed202473b1fb54a5997a7db8c6d8523" + integrity sha512-jUlyaDXts7TW2CqQ4GaO5VJ4PwwaV8VUGA7+km3n6k6xtOEacf61u0VXwN80phY/evMcaS+9eIeJ9MOyDxt5Zw== + dependencies: + "@types/resolve" "0.0.8" + builtin-modules "^3.1.0" + is-module "^1.0.0" + resolve "^1.11.1" + rollup-pluginutils "^2.8.1" + rollup-plugin-replace@^2.0.0, rollup-plugin-replace@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/rollup-plugin-replace/-/rollup-plugin-replace-2.2.0.tgz#f41ae5372e11e7a217cde349c8b5d5fd115e70e3" @@ -18780,6 +19076,15 @@ rollup@^1.0.0, rollup@^1.10.0, rollup@^1.15.1: "@types/node" "^12.0.10" acorn "^6.1.1" +rollup@^1.20.3: + version "1.20.3" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.20.3.tgz#6243f6c118ca05f56b2d9433112400cd834a1eb8" + integrity sha512-/OMCkY0c6E8tleeVm4vQVDz24CkVgvueK3r8zTYu2AQNpjrcaPwO9hE+pWj5LTFrvvkaxt4MYIp2zha4y0lRvg== + dependencies: + "@types/estree" "0.0.39" + "@types/node" "^12.7.2" + acorn "^7.0.0" + rst-selector-parser@^2.2.3: version "2.2.3" resolved "https://registry.yarnpkg.com/rst-selector-parser/-/rst-selector-parser-2.2.3.tgz#81b230ea2fcc6066c89e3472de794285d9b03d91" @@ -18993,6 +19298,17 @@ sass-loader@^7.1.0: pify "^3.0.0" semver "^5.5.0" +sass-loader@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-8.0.0.tgz#e7b07a3e357f965e6b03dd45b016b0a9746af797" + integrity sha512-+qeMu563PN7rPdit2+n5uuYVR0SSVwm0JsOUsaJXzgYcClWSlmX0iHDnmeOobPkf5kUglVot3QS6SyLyaQoJ4w== + dependencies: + clone-deep "^4.0.1" + loader-utils "^1.2.3" + neo-async "^2.6.1" + schema-utils "^2.1.0" + semver "^6.3.0" + sass@^1.22.0: version "1.22.3" resolved "https://registry.yarnpkg.com/sass/-/sass-1.22.3.tgz#b3591191ab0f3caece39ed9384c90caccacf471c" @@ -19090,6 +19406,14 @@ schema-utils@^1.0.0: ajv-errors "^1.0.0" ajv-keywords "^3.1.0" +schema-utils@^2.0.0, schema-utils@^2.0.1, schema-utils@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.2.0.tgz#48a065ce219e0cacf4631473159037b2c1ae82da" + integrity sha512-5EwsCNhfFTZvUreQhx/4vVQpJ/lnCAkgoIHLhSpp4ZirE+4hzFvdJi0FMub6hxbFVBJYSpeVVmon+2e7uEGRrA== + dependencies: + ajv "^6.10.2" + ajv-keywords "^3.4.1" + scss-comment-parser@^0.8.4: version "0.8.4" resolved "https://registry.yarnpkg.com/scss-comment-parser/-/scss-comment-parser-0.8.4.tgz#8e82c3fcf7fdbbb7f172f8955e2aa88b685f86d8" @@ -19352,6 +19676,13 @@ shallow-clone@^1.0.0: kind-of "^5.0.0" mixin-object "^2.0.1" +shallow-clone@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" + integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== + dependencies: + kind-of "^6.0.2" + shallow-equal@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shallow-equal/-/shallow-equal-1.2.0.tgz#fd828d2029ff4e19569db7e19e535e94e2d1f5cc" @@ -20298,6 +20629,14 @@ style-loader@^0.23.1: loader-utils "^1.1.0" schema-utils "^1.0.0" +style-loader@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-1.0.0.tgz#1d5296f9165e8e2c85d24eee0b7caf9ec8ca1f82" + integrity sha512-B0dOCFwv7/eY31a5PCieNwMgMhVGFe9w+rh7s/Bx8kfFkrth9zfTZquoYvdw8URgiqxObQKcpW51Ugz1HjfdZw== + dependencies: + loader-utils "^1.2.3" + schema-utils "^2.0.1" + style-search@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902"