diff --git a/.babelrc b/.babelrc index b65be9bef..a0934e245 100644 --- a/.babelrc +++ b/.babelrc @@ -1,16 +1,76 @@ { "presets": [ - ["es2015", { "modules": false }], + ["es2015", { + "modules": false + }], "es2016", - "react" + "react", + "flow" ], "plugins": [ "transform-class-properties", - "transform-object-rest-spread" + "transform-object-rest-spread", + "transform-regenerator" ], "env": { + "dev": { + "presets": [ + ["env", { + "modules": false, + "targets": { + "browsers": ["last 1 Chrome versions", "last 1 Firefox versions"] + } + }], + "stage-1", + "react", + "flow" + ], + "plugins": [ + "flow-react-proptypes", [ + "react-intl", + { + "enforceDescriptions": true, + "messagesDir": "./i18n/json" + } + ] + ] + }, + "production": { + "presets": [ + ["env", { + "modules": false + }], + "stage-1", + "react", + "flow" + ], + "plugins": [ + [ + "react-intl", + { + "enforceDescriptions": true, + "messagesDir": "./i18n/json" + } + ] + ] + }, "npm": { + "presets": [ + ["env", { + "modules": false + }], + "stage-1", + "react", + "flow" + ], "plugins": [ + [ + "react-intl", + { + "enforceDescriptions": true, + "messagesDir": "./i18n/json" + } + ], [ "babel-plugin-transform-require-ignore", { "extensions": [".scss", ".css"] @@ -19,8 +79,22 @@ ] }, "test": { + "presets": [ + ["env", { + "modules": false + }], + "stage-1", + "react", + "flow" + ], "plugins": [ - "transform-es2015-modules-commonjs", + "transform-es2015-modules-commonjs", [ + "react-intl", + { + "enforceDescriptions": false, + "messagesDir": "./i18n/json" + } + ], [ "babel-plugin-transform-require-ignore", { "extensions": [".scss", ".css"] diff --git a/.eslintignore b/.eslintignore index 4674fa221..a4296d79d 100644 --- a/.eslintignore +++ b/.eslintignore @@ -3,3 +3,5 @@ dist/* docs/* lib/* index.js +flow/** +flow-typed/** \ No newline at end of file diff --git a/.eslintrc b/.eslintrc index d5a4e62e9..7cabf241e 100644 --- a/.eslintrc +++ b/.eslintrc @@ -2,7 +2,10 @@ "parser": "babel-eslint", "extends": [ "airbnb", + "plugin:flowtype/recommended", + "plugin:react/recommended", "prettier", + "prettier/flowtype", "prettier/react" ], "env": { @@ -31,102 +34,57 @@ "jest": false }, "rules": { - "quotes": [ - "error", - "single" - ], - "comma-dangle": [ - "error", - "never" - ], - "indent": [ - "error", - 4, - { - "SwitchCase": 1 + "camelcase": ["off"], + "react/jsx-boolean-value": ["off"], + "react/no-unused-prop-types": ["off"], + "react/default-props-match-prop-types": ["off", { + "allowRequiredDefaults": true + }], + "react/sort-comp": ["off"], + "react/forbid-prop-types": ["off"], + "no-param-reassign": ["error", { + "props": false + }], + "react/require-default-props": ["off"], + "react/display-name": ["off"], + "quotes": ["error", "single"], + "comma-dangle": ["error", "never"], + "indent": ["error", 4, { + "SwitchCase": 1 + }], + "import/imports-first": ["off"], + "jsx-quotes": ["error", "prefer-single"], + "max-len": ["off"], + "react/jsx-indent-props": ["error", 4], + "react/jsx-indent": ["error", 4], + "no-underscore-dangle": ["off"], + "react/jsx-filename-extension": ["off"], + "arrow-body-style": ["off"], + "class-methods-use-this": ["off"], + "arrow-parens": ["error", "always"], + "no-plusplus": ["error", { + "allowForLoopAfterthoughts": true + }], + "import/no-extraneous-dependencies": ["off"], + "import/no-webpack-loader-syntax": ["off"], + "valid-jsdoc": ["warn", { + "prefer": { + "returns": "return", + "class": "constructor" + }, + "preferType": { + "array": "Array", + "function": "Function", + "object": "Object", + "Boolean": "boolean", + "Number": "number", + "String": "string" } - ], - "import/imports-first": [ - "off" - ], - "jsx-quotes": [ - "error", - "prefer-single" - ], - "max-len": [ - "off" - ], - "react/jsx-indent-props": [ - "error", - 4 - ], - "react/jsx-indent": [ - "error", - 4 - ], - "no-underscore-dangle": [ - "off" - ], - "react/jsx-filename-extension": [ - "off" - ], - "arrow-body-style": [ - "off" - ], - "class-methods-use-this": [ - "off" - ], - "arrow-parens": [ - "error", - "always" - ], - "no-plusplus": [ - "error", - { - "allowForLoopAfterthoughts": true - } - ], - "import/no-extraneous-dependencies": [ - "off" - ], - "import/no-webpack-loader-syntax": [ - "off" - ], - "require-jsdoc": [ - "warn", - { - "require": { - "FunctionDeclaration": true, - "MethodDefinition": false, - "ClassDeclaration": false, - "ArrowFunctionExpression": true - } - } - ], - "valid-jsdoc": [ - "warn", - { - "prefer": { - "returns": "return", - "class": "constructor" - }, - "preferType": { - "array": "Array", - "function": "Function", - "object": "Object", - "Boolean": "boolean", - "Number": "number", - "String": "string" - } - } - ], - "prefer-destructuring": [ - "error", - { - "object": true, - "array": false - } - ] + }], + "prefer-destructuring": ["error", { + "object": true, + "array": false + }] }, "settings": { "import/resolver": { diff --git a/.flowconfig b/.flowconfig new file mode 100644 index 000000000..f7d387a1b --- /dev/null +++ b/.flowconfig @@ -0,0 +1,35 @@ +[ignore] +.*/build/.* +.*/lib/.* +.*/functional-tests/.* +.*/test-utils/.* +.*/reports/.* +.*/node_modules/babel-plugin-flow-react-proptypes.* +.*/node_modules/conventional-changelog* +.*/node_modules/eslint* +.*/node_modules/jest* +.*/node_modules/npm-shrinkwrap.* +.*/node_modules/stylelint.* +.*/node_modules/webpack* +.*/node_modules/draft-js* +.*/node_modules/findup* +.*/node_modules/rangy* + +[include] +./src + +[libs] + +[options] +module.name_mapper.extension='scss' -> '/flow/SCSSFlowStub.js.flow' +module.name_mapper.extension='css' -> '/flow/SCSSFlowStub.js.flow' +module.name_mapper='react-intl-locale-data' -> '/flow/WebpackI18N.js.flow' +module.name_mapper='box-annotations-locale-data' -> '/flow/WebpackI18N.js.flow' +module.name_mapper='box-react-ui-locale-data' -> '/flow/WebpackI18N.js.flow' +module.name_mapper='draft-js' -> '/flow/DraftJSFlowStub.js.flow' +module.name_mapper='draft-js/EditorState' -> '/flow/DraftJSFlowStub.js.flow' +module.name_mapper='rangy' -> '/flow/Rangy.js.flow' +module.name_mapper='rangy/lib/rangy-classapplier' -> '/flow/Rangy.js.flow' +module.name_mapper='rangy/lib/rangy-highlighter' -> '/flow/Rangy.js.flow' +module.name_mapper='rangy/lib/rangy-selectionsaverestore' -> '/flow/Rangy.js.flow' +suppress_comment= \\(.\\|\n\\)*\\$FlowFixMe diff --git a/.stylelintrc b/.stylelintrc index de3917636..0ccbd730e 100644 --- a/.stylelintrc +++ b/.stylelintrc @@ -7,7 +7,7 @@ "rules": { "indentation": 4, "at-rule-no-vendor-prefix": true, - "at-rule-no-unknown": [true, { "ignoreAtRules": ["include", "mixin"] }], + "at-rule-no-unknown": [true, { "ignoreAtRules": ["include", "mixin", "extend"] }], "media-feature-name-no-vendor-prefix": true, "property-no-vendor-prefix": true, "selector-no-vendor-prefix": true, @@ -17,4 +17,4 @@ "no-descending-specificity": null, "order/properties-alphabetical-order": [true, { "severity": "warning" }] } -} +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 7b76b7dc2..0acebedd4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,14 +1,13 @@ // Place your settings in this file to overwrite default and user settings. { - "editor.rulers": [ - 120 - ], - "flow.enabled": false, + "typescript.validate.enable": false, + "typescript.format.enable": false, + "flow.pathToFlow": "${workspaceRoot}/node_modules/.bin/flow", "flow.useNPMPackagedFlow": true, + "flow.enabled": true, + "javascript.validate.enable": false, "prettier.eslintIntegration": true, "prettier.printWidth": 120, - "prettier.singleQuote": true, "prettier.tabWidth": 4, - "typescript.format.enable": false, - "typescript.validate.enable": false + "prettier.singleQuote": true } diff --git a/build/TranslationsPlugin.js b/build/TranslationsPlugin.js new file mode 100644 index 000000000..d619fed3f --- /dev/null +++ b/build/TranslationsPlugin.js @@ -0,0 +1,19 @@ +/* eslint-disable strict */ + +'use strict'; + +const path = require('path'); +const buildTranslations = require('box-react-ui/lib/build-utils/buildTranslations'); + +const i18n = path.resolve('i18n'); // Where the .properties files are dumped +const jsonDir = path.join(i18n, 'json'); // Where the react-intl plugin dumps json + +function TranslationsPlugin() {} +TranslationsPlugin.prototype.buildTranslations = () => { + buildTranslations(i18n, jsonDir); +}; +TranslationsPlugin.prototype.apply = function apply(compiler) { + compiler.plugin('done', this.buildTranslations); +}; + +module.exports = TranslationsPlugin; diff --git a/build/build_locale.js b/build/build_locale.js new file mode 100644 index 000000000..6bf346c98 --- /dev/null +++ b/build/build_locale.js @@ -0,0 +1,20 @@ +const { execSync } = require('child_process'); + +/** + * Build a single locale + * + * @param {string} locale - locale to build + * @param {*} callback - callback from worker-farm master process + * @return {void} + */ +module.exports = (locale, callback) => { + try { + console.log(`Building ${locale}`); + // build assets for a single locale + execSync(`time LANGUAGE=${locale} yarn run build-prod`); + callback(); + } catch (error) { + console.error(`Error: Failed to build ${locale}`); + callback(true); + } +}; diff --git a/build/enzyme-adapter.js b/build/enzyme-adapter.js new file mode 100644 index 000000000..c4fc6d8c9 --- /dev/null +++ b/build/enzyme-adapter.js @@ -0,0 +1,7 @@ +import 'core-js/es6/map'; +import 'core-js/es6/set'; +import 'raf/polyfill'; +import Enzyme from 'enzyme'; +import Adapter from 'enzyme-adapter-react-16'; + +Enzyme.configure({ adapter: new Adapter() }); diff --git a/build/prepush.sh b/build/prepush.sh new file mode 100755 index 000000000..aa0f46bf9 --- /dev/null +++ b/build/prepush.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +# translation properties file +PROPERTIES="i18n/en-US.properties" + +# commit updated translations if any +check_and_commit_updated_translations() { + if ! git diff --quiet HEAD $PROPERTIES; then + echo "--------------------------------------------------------" + echo "Committing updated translations" + echo "--------------------------------------------------------" + git add $PROPERTIES || exit 1 + git commit --amend --no-edit --no-verify || exit 1 + echo "--------------------------------------------------------" + echo "Amended commit with translations, please push again with --no-verify" + echo "--------------------------------------------------------" + exit 1 + fi +} + +# lint, test, and build assets to update translations +prepush() { + echo "--------------------------------------------------------" + echo "Linting" + echo "--------------------------------------------------------" + yarn lint || exit 1 + + echo "--------------------------------------------------------" + echo "Checking flow types" + echo "--------------------------------------------------------" + yarn flow || exit 1 + + echo "--------------------------------------------------------" + echo "Testing" + echo "--------------------------------------------------------" + yarn test || exit 1 + + echo "--------------------------------------------------------" + echo "Building" + echo "--------------------------------------------------------" + yarn build || exit 1 + + check_and_commit_updated_translations +} + +# Execute this script +if ! prepush; then + echo "----------------------------------------------------" + echo "Error: failure in prepush script" + echo "----------------------------------------------------" + exit 1 +fi diff --git a/build/prod.js b/build/prod.js new file mode 100644 index 000000000..6bef755e6 --- /dev/null +++ b/build/prod.js @@ -0,0 +1,31 @@ +const workerFarm = require('worker-farm'); +const locales = require('box-locales'); +const numCPUs = require('os').cpus().length; +const { execSync } = require('child_process'); +const path = require('path'); + +const filename = path.basename(__filename); +const bundleCount = locales.length * 2; // One with react, and one without + +let counter = 0; +const workers = workerFarm( + { + maxConcurrentWorkers: numCPUs - 2, + maxRetries: 0 + }, + require.resolve('./build_locale.js') +); + +locales.forEach((locale) => { + workers(locale, (error) => { + if (++counter === bundleCount || error) { // eslint-disable-line + // terminate after all locales have been processed + workerFarm.end(workers); + } + + if (error) { + // kill the node process that spawns the workers as well as all processes been spawned + execSync(`ps ax | grep "${filename}" | cut -b1-06 | xargs -t kill`); + } + }); +}); diff --git a/build/props-to-es2015.js b/build/props-to-es2015.js new file mode 100644 index 000000000..488898f18 --- /dev/null +++ b/build/props-to-es2015.js @@ -0,0 +1 @@ +require('./TranslationsPlugin').prototype.buildTranslations(); diff --git a/build/publish.sh b/build/publish.sh index c1f23a07c..9d52d7bc6 100755 --- a/build/publish.sh +++ b/build/publish.sh @@ -67,6 +67,21 @@ lint_and_test() { fi + echo "----------------------------------------------------" + echo "Running flow for version" $VERSION + echo "----------------------------------------------------" + if yarn run flow; then + echo "----------------------------------------------------" + echo "Done flowing for version" $VERSION + echo "----------------------------------------------------" + else + echo "----------------------------------------------------" + echo "Failed flowing!" + echo "----------------------------------------------------" + exit 1; + fi + + echo "----------------------------------------------------" echo "Running tests for version" $VERSION echo "----------------------------------------------------" diff --git a/build/styleguide.config.js b/build/styleguide.config.js new file mode 100644 index 000000000..380d42891 --- /dev/null +++ b/build/styleguide.config.js @@ -0,0 +1,30 @@ +const path = require('path'); +const { version } = require('../package.json'); +const webpackConf = require('./styleguide.webpack.config.js'); + +module.exports = { + webpackConfig: Array.isArray(webpackConf) ? webpackConf[0] : webpackConf, + styleguideDir: path.join(__dirname, '../styleguide'), + // @NOTE (wyu): This is how you enable source-map for styleguidist + dangerouslyUpdateWebpackConfig(webpackConfig) { + webpackConfig.devtool = 'source-map'; + return webpackConfig; + }, + sections: [ + { + name: 'Components', + components: '../src/components/**/[A-Z]*.js' + } + ], + title: `Box Annotations ${version}`, + theme: { + color: { + link: '#777', + linkHover: '#0061d5' + }, + fontFamily: { + base: 'Lato, "Helvetica Neue", Helvetica, Arial, sans-serif' + } + }, + pagePerSection: true +}; diff --git a/build/styleguide.webpack.config.js b/build/styleguide.webpack.config.js new file mode 100644 index 000000000..3fb62309d --- /dev/null +++ b/build/styleguide.webpack.config.js @@ -0,0 +1,63 @@ +const path = require('path'); +const { DefinePlugin } = require('webpack'); + +const language = 'en-US'; +const locale = 'en'; + +module.exports = { + module: { + rules: [ + { + test: /\.js$/, + exclude: /(node_modules)/, + loader: 'babel-loader' + }, + { + test: /\.s?css$/, + use: ['style-loader', 'css-loader', 'sass-loader'] + }, + { + test: /\.html$/, + loader: 'file-loader', + options: { + name: '[name].[ext]' + } + }, + { + test: /\.(svg|html)$/, + loader: 'raw-loader', + exclude: [path.resolve('node_modules')] + }, + { + test: /\.(jpe?g|png|gif|woff2|woff)$/, + loader: 'file-loader', + options: { + name: '[name].[ext]' + }, + exclude: [path.resolve('node_modules')] + } + ] + }, + plugins: [ + new DefinePlugin({ + __NAME__: JSON.stringify('name'), + __VERSION__: JSON.stringify('version'), + __LANGUAGE__: JSON.stringify(language) + }) + ], + resolve: { + alias: { + // Map to uncompiled source code so we get nice source maps for debugging + 'box-annotations/lib': path.join(__dirname, '../src'), + 'react-intl-locale-data': path.resolve(`node_modules/react-intl/locale-data/${locale}`), + 'box-annotations-locale-data': path.resolve(`i18n/${language}`), + 'box-react-ui-locale-data': path.resolve(`node_modules/box-react-ui/i18n/${language}`), + examples: path.join(__dirname, '../examples/src'), + Wrapper: path.join(__dirname, '../examples/Wrapper'), + 'rsg-components/Wrapper': path.join( + __dirname, + '../examples/Wrapper', + ), + } + } +}; diff --git a/build/upgrade_brui.sh b/build/upgrade_brui.sh index f2793c440..37529a12b 100644 --- a/build/upgrade_brui.sh +++ b/build/upgrade_brui.sh @@ -81,6 +81,9 @@ upgrade_brui() { # Bump the version number update_version || return 1 + # Update flow-typed configs + yarn flow-typed-update + # Push to GitHub push_to_github || return 1 diff --git a/build/webpack.common.config.js b/build/webpack.common.config.js index 4968b134e..addc5e794 100644 --- a/build/webpack.common.config.js +++ b/build/webpack.common.config.js @@ -1,10 +1,11 @@ const path = require('path'); -const webpack = require('webpack'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); -const pkg = require('../package.json'); +const { DefinePlugin, NormalModuleReplacementPlugin } = require('webpack'); +const packageJSON = require('../package.json'); -const { DefinePlugin } = webpack; -const NormalPlugin = webpack.NormalModuleReplacementPlugin; +const language = process.env.LANGUAGE; +const isRelease = process.env.NODE_ENV === 'production'; +const version = isRelease ? packageJSON.version : 'dev'; /* eslint-disable global-require */ /* eslint-disable import/no-dynamic-require */ @@ -21,7 +22,7 @@ module.exports = () => { rules: [ { test: /\.js$/, - use: 'babel-loader', + loader: 'babel-loader', exclude: [path.resolve('node_modules')] }, { @@ -44,18 +45,19 @@ module.exports = () => { ] }, plugins: [ - new MiniCssExtractPlugin({ - filename: '[name].css' - }), new DefinePlugin({ - __NAME__: JSON.stringify(pkg.name), - __VERSION__: JSON.stringify(pkg.version), + __NAME__: JSON.stringify(packageJSON.name), + __LANGUAGE__: JSON.stringify(language), + __VERSION__: JSON.stringify(version), 'process.env': { NODE_ENV: JSON.stringify(process.env.NODE_ENV), BABEL_ENV: JSON.stringify(process.env.BABEL_ENV) } }), - new NormalPlugin(/\/iconv-loader$/, 'node-noop') + new MiniCssExtractPlugin({ + filename: '[name].css' + }), + new NormalModuleReplacementPlugin(/\/iconv-loader$/) ], stats: { assets: true, diff --git a/build/webpack.config.js b/build/webpack.config.js index a042fcf3a..1d495d60e 100644 --- a/build/webpack.config.js +++ b/build/webpack.config.js @@ -1,18 +1,22 @@ require('babel-polyfill'); - -const isRelease = process.env.NODE_ENV === 'production'; -const isDev = process.env.NODE_ENV === 'dev'; - const path = require('path'); +const CircularDependencyPlugin = require('circular-dependency-plugin'); const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin'); -const RsyncPlugin = require('./RsyncPlugin'); const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); const { BannerPlugin } = require('webpack'); const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer'); -const commonConfig = require('./webpack.common.config'); -const license = require('./license'); const fs = require('fs'); +const license = require('./license'); +const commonConfig = require('./webpack.common.config'); +const TranslationsPlugin = require('./TranslationsPlugin'); +const RsyncPlugin = require('./RsyncPlugin'); + +const isRelease = process.env.NODE_ENV === 'production'; +const isDev = process.env.NODE_ENV === 'dev'; +const language = process.env.LANGUAGE; +const locale = language.substr(0, language.indexOf('-')); + let rsyncLocation = ''; if (fs.existsSync('build/rsync.json')) { /* eslint-disable */ @@ -29,6 +33,16 @@ const config = Object.assign(commonConfig(), { output: { path: path.resolve('lib'), filename: '[Name].js' + }, + resolve: { + modules: ['src', 'node_modules'], + alias: { + examples: path.join(__dirname, '../examples/src'), + 'react-intl-locale-data': path.resolve(`node_modules/react-intl/locale-data/${locale}`), + 'box-annotations-locale-data': path.resolve(`i18n/${language}`), + 'box-react-ui-locale-data': path.resolve(`node_modules/box-react-ui/i18n/${language}`), + moment: path.resolve('src/MomentShim') // Hack to leverage Intl instead + } } }); @@ -40,16 +54,23 @@ if (isDev) { // Add inline source map config.devtool = 'inline-source-map'; + config.plugins.push(new TranslationsPlugin()); + config.plugins.push( + new CircularDependencyPlugin({ + exclude: /node_modules/, + failOnError: true + }) + ); } -if (isRelease) { +if (isRelease && language === 'en-US') { config.plugins.push( new BundleAnalyzerPlugin({ analyzerMode: 'static', openAnalyzer: false, - reportFilename: '../reports/webpack-stats.html', + reportFilename: path.resolve('../reports/webpack-stats.html'), generateStatsFile: true, - statsFilename: '../reports/webpack-stats.json' + statsFilename: path.resolve('../reports/webpack-stats.json`') }) ); diff --git a/docs/thread.md b/docs/thread.md index b063742ba..32b08284c 100644 --- a/docs/thread.md +++ b/docs/thread.md @@ -11,8 +11,8 @@ The following methods are available for the annotation threads. | show | Shows the annotation indicator | || | hide | Hides the annotation indicator | || | reset | Resets thread state to 'inactive' | || -| showDialog | Shows the appropriate dialog for this thread | || -| hideDialog | Hides the appropriate indicator for this thread | || +| renderAnnotationPopover | Shows the appropriate dialog for this thread | || +| unmountPopover | Hides the appropriate indicator for this thread | || | saveAnnotation | Saves an annotation locally and on the server | {string} annotation type, {text} text of annotation to save || | deleteAnnotation | Deletes an annotation | {string} annotation ID, {boolean} whether or not to delete on server, default true || diff --git a/examples/Examples.scss b/examples/Examples.scss new file mode 100644 index 000000000..967d8fb0f --- /dev/null +++ b/examples/Examples.scss @@ -0,0 +1,27 @@ +@import '../src/common'; + +.ba .annotation-container { + margin-top: 10px; + padding-bottom: 10px; + + .ba-popover { + position: relative; + width: fit-content; + } + + @media #{$mobile}, #{$tablet} { + border: 1px solid $seesee; + height: 400px; + overflow: hidden; + + .ba-popover { + width: 100%; + } + } +} + +.action-controls-container { + border: 1px solid $see-see; + border-radius: 3px; + margin: 10px; +} diff --git a/examples/Wrapper.js b/examples/Wrapper.js new file mode 100644 index 000000000..f1fbea21c --- /dev/null +++ b/examples/Wrapper.js @@ -0,0 +1,23 @@ +// @flow +/** + * Wrapper component for styleguidist examples + */ +// $FlowFixMe +import 'core-js'; // For IE11 +import * as React from 'react'; + +import Internationalize from '../src/components/Internationalize'; + +import './Examples.scss'; + +type Props = { + children: React.Node +}; + +const Wrapper = ({ children }: Props) => ( + + {children} + +); + +export default Wrapper; diff --git a/examples/src/AnnotationPopoverExample.js b/examples/src/AnnotationPopoverExample.js new file mode 100644 index 000000000..26ee34275 --- /dev/null +++ b/examples/src/AnnotationPopoverExample.js @@ -0,0 +1,146 @@ +import React from 'react'; + +/* eslint-disable-next-line */ +import AnnotationPopover from 'box-annotations/lib/components/AnnotationPopover'; + +const USER1 = { + type: 'user', + id: '1', + name: 'Dominic Toretto', + email: 'fast@furious.com' +}; + +const USER2 = { + type: 'user', + id: '4', + name: 'Mia Thermopolis', + email: 'princess@genovia.gov' +}; + +const createdAt = '2017-08-27T10:40:41-07:00'; + +const onDelete = () => {}; +const onCreate = () => {}; +const onCancel = () => {}; +const position = () => {}; + +const annotationInfo = { + createdAt, + createdBy: USER1 +} + +const comments = [ + { + id: '123defg', + message: 'FAMILY', + permissions: { + can_delete: true + }, + onDelete, + ...annotationInfo + }, + { + id: '123defh', + message: 'FAMILY', + permissions: { + can_delete: true + }, + onDelete, + ...annotationInfo + }, + { + id: '123defi', + message: 'FAMILY', + permissions: { + can_delete: true + }, + onDelete, + ...annotationInfo + }, + { + id: '123def', + message: 'FAMILY', + permissions: { + can_delete: true + }, + onDelete, + ...annotationInfo + }, + { + id: '456def', + createdAt, + createdBy: USER2, + message: 'I\'m a princess?', + permissions: {}, + onDelete, + isPending: true + }, + { + id: '789ghi', + createdAt, + createdBy: USER1, + message: 'WASSUP', + permissions: { + can_delete: true + }, + onDelete + } +]; + +const AnnotationPopoverContainer = (props) => ( +
+ +
+); + +const ListPopover = () => ( + +); + +const PointCreatePopover = () => ( + +); + +const HighlightCreatePopover = () => ( + +); + +const HighlightCommentCreatePopover = () => ( + +); + +const DrawCreatePopover = () => ( + +); + +const CannotAnnotatePopover = () => ( + +); + +const PlainHighlightAnnotation = () => ( + +); + +const HighlightCommentAnnotation = () => ( + +); + +const DrawingAnnotation = () => ( + +); + +const AnnotationPopoverExample = () => ( +
+ + + + + + + + + +
+); + +export default AnnotationPopoverExample; \ No newline at end of file diff --git a/examples/src/CommentListExample.js b/examples/src/CommentListExample.js new file mode 100644 index 000000000..fe1cf7368 --- /dev/null +++ b/examples/src/CommentListExample.js @@ -0,0 +1,97 @@ +import React from 'react'; + +/* eslint-disable-next-line */ +import CommentList from 'box-annotations/lib/components/CommentList'; + +const USER1 = { + type: 'user', + id: '1', + name: 'Dominic Toretto', + email: 'fast@furious.com' +}; + +const USER2 = { + type: 'user', + id: '4', + name: 'Mia Thermopolis', + email: 'princess@genovia.gov' +}; + +const USER3 = { + type: 'user', + id: '8', + name: 'Brian O\'Conner', + email: '2fast@furious.com' +}; + +const createdAt = '2017-08-27T10:40:41-07:00'; +const modifiedAt = '2017-08-27T10:40:41-07:00'; + +const error = { + action: { + onAction: () => {}, + text: 'This does things' + }, + message: { id: '123', defaultMessage: 'Something happened' }, + title: { id: '456', defaultMessage: 'Uh Oh!' } +} + +const onDelete = () => {}; + +const comments = [ + { + id: '123def', + createdAt, + modifiedAt, + createdBy: USER1, + message: 'FAMILY', + permissions: {}, + onDelete + }, + { + id: '456def', + createdAt, + modifiedAt, + createdBy: USER2, + message: 'I\'m a princess?', + permissions: {}, + onDelete, + isPending: true + }, + { + id: '789ghi', + createdAt, + modifiedAt, + createdBy: USER3, + message: 'I\'m not a cop! I\'m not a cop! I\'m not a cop! I\'m not a cop! I\'m not a cop! I\'m not a cop! I\'m not a cop! I\'m not a cop! I\'m not a cop! I\'m not a cop! I\'m not a cop! I\'m not a cop! I\'m not a cop! I\'m not a cop! I\'m not a cop! I\'m not a cop! I\'m not a cop! I\'m not a cop! I\'m not a cop! I\'m not a cop! I\'m not a cop! ', + permissions: { + can_delete: true + }, + onDelete + }, + { + id: '321cba', + createdAt, + modifiedAt, + message: 'Knock? Knock?', + permissions: {} + }, + { + id: '654fed', + createdAt, + modifiedAt, + createdBy: USER3, + message: 'WHOOPS!', + permissions: {}, + onDelete, + error + } +]; + +const CommentListExamples = () => ( +
+ +
+); + +export default CommentListExamples; \ No newline at end of file diff --git a/examples/src/DrawingControlsExamples.js b/examples/src/DrawingControlsExamples.js new file mode 100644 index 000000000..5ed5ae847 --- /dev/null +++ b/examples/src/DrawingControlsExamples.js @@ -0,0 +1,24 @@ +import React from 'react'; + +/* eslint-disable-next-line */ +import ActionControls from 'box-annotations/lib/components/ActionControls'; + +const onDelete = () => {}; + +const ActionControlsContainer = (props) => ( +
+ +
+); + +const DrawingControls = () => ( + +); + +const DrawingControlsExamples = () => ( +
+ +
+); + +export default DrawingControlsExamples; \ No newline at end of file diff --git a/examples/src/HighlightControlsExamples.js b/examples/src/HighlightControlsExamples.js new file mode 100644 index 000000000..53624701b --- /dev/null +++ b/examples/src/HighlightControlsExamples.js @@ -0,0 +1,41 @@ +import React from 'react'; + +/* eslint-disable-next-line */ +import ActionControls from 'box-annotations/lib/components/ActionControls'; + +const onCreate = () => {}; +const onCommentClick = () => {}; + +const ActionControlsContainer = (props) => ( +
+ +
+); + +const PendingPlainHighlightControls = () => ( + +); + +const PlainHighlightControls = () => ( + +); + +const PendingHighlightCommentControls = () => ( + +); + +const HighlightCommentControls = () => ( + +); + + +const HighlightControlsExamples = () => ( +
+ + + + +
+); + +export default HighlightControlsExamples; \ No newline at end of file diff --git a/examples/src/index.js b/examples/src/index.js new file mode 100644 index 000000000..69b331f55 --- /dev/null +++ b/examples/src/index.js @@ -0,0 +1,4 @@ +export { default as CommentListExample } from './CommentListExample'; +export { default as DrawingControlsExamples } from './DrawingControlsExamples'; +export { default as HighlightControlsExamples } from './HighlightControlsExamples'; +export { default as AnnotationPopoverExample } from './AnnotationPopoverExample'; \ No newline at end of file diff --git a/flow-typed/box-annotations.js b/flow-typed/box-annotations.js new file mode 100644 index 000000000..5be8213e7 --- /dev/null +++ b/flow-typed/box-annotations.js @@ -0,0 +1,150 @@ +/** + * @flow + * @file Flow types + * @author Box + */ +/* eslint-disable no-use-before-define */ +import type { $AxiosError, Axios, CancelTokenSource } from 'axios'; +import EventEmitter from 'events'; +import AnnotationThread from '../src/AnnotationThread'; +import DrawingThread from '../src/draw/DrawingThread'; +import DocHighlightThread from '../src/doc/DocHighlightThread'; +import DrawingPath from '../src/drawing/DrawingPath'; +import CreateHighlightDialog from '../src/doc/CreateHighlightDialog'; + +type StringMap = { [string]: string }; +type AnnotationPermissions = { + can_edit: boolean, + can_delete: boolean +}; + +type BoxItemPermissions = { + can_annotate: boolean, + can_view_annotations_all: boolean, + can_view_annotations_self: boolean +}; + +type AnnotationType = 'point' | 'plain-highlight' | 'highlight-comment' | 'draw'; + +type Coordinates = { + x: number, + y: number +}; + +// [x1, x2, x3, x4, y1, y2, y3 ,y4] +type QuadPoint = { + x1: number, + y1: number, + x2: number, + y2: number, + x3: number, + y3: number, + x4: number, + y4: number +}; +type QuadPoints = Array; + +type Path = { + path: Array +}; +type DrawingPaths = Array; + +type Dimensions = { + x: number, + y: number +} + +type LocationInfo = { + dimensions: Dimensions, + page: number +}; + +type PointLocationInfo = Coordinates & LocationInfo; + +type HighlightLocationInfo = { + quadpoints: QuadPoints +} & LocationInfo; + +type DrawingLocationInfo = { + minX: number, + minY: number, + maxX: number, + maxY: number, + paths: DrawingPaths +} & LocationInfo; + +type Location = PointLocationInfo | HighlightLocationInfo | DrawingLocationInfo; + +type User = { + type: 'user', + id: string, + email: string, + name?: string, + avatarUrl?: string +}; + +type CommentProps = { + id: string, + message: string, + permissions: AnnotationPermissions, + createdBy?: User, + createdAt: string, + modifiedAt?: string, + isPending: boolean +}; + +type Comments = Array; + +type BoxFileVersion = { + id: string, + type: 'file_version' +}; + +type Annotation = { + id?: string, + type: AnnotationType, + location?: Location, + threadNumber?: string, + comments: Comments, + createdBy?: User, + createdAt?: string, + canAnnotate: boolean, + canDelete: boolean +} + +type Options = { + apiHost: string, + fileId: string, + token: string, + anonymousUserName: string, + permissions: BoxItemPermissions +}; + +type AnnotationDetails = { + threadID: string, + type: AnnotationType, + location: Location +}; + +type BoxUser = { + type: 'user', + id: string, + login: string, + name: string, + profile_image: string +} + +type AnnotationData = { + id: string, + details: AnnotationDetails, + item: BoxFileVersion, + message: string, + permissions: AnnotationPermissions, + created_by: BoxUser, + created_at: string, + modified_at: string, + thread: string +}; + +type StringAnyMap = { [string]: any }; +type AnnotationMap = { [string]: AnnotationData }; \ No newline at end of file diff --git a/flow-typed/box-ui-elements.js b/flow-typed/box-ui-elements.js new file mode 100644 index 000000000..e26322474 --- /dev/null +++ b/flow-typed/box-ui-elements.js @@ -0,0 +1,43 @@ +/** + * @flow + * @file Flow types + * @author Box + */ +/* eslint-disable no-use-before-define */ +import type { MessageDescriptor, InjectIntlProvidedProps } from 'react-intl'; + +type SelectorItem = { + id: string, + name: string, + item: Object, + value?: any +}; + +type SelectorItems = Array; + +type ActionItemError = { + title: MessageDescriptor, + message: MessageDescriptor, + action?: { + text: MessageDescriptor, + onAction: Function + } +}; + +type BoxItemPermission = { + can_comment?: boolean, + can_edit_comment?: boolean, + can_delete_comment?: boolean, + can_preview?: boolean, + can_rename?: boolean, + can_download?: boolean, + can_delete?: boolean, + can_upload?: boolean, + can_share?: boolean, + can_set_share_access?: boolean +}; + +type Translations = { + translationEnabled?: boolean, + onTranslate?: Function +}; \ No newline at end of file diff --git a/flow-typed/npm/box-react-ui_vx.x.x.js b/flow-typed/npm/box-react-ui_vx.x.x.js new file mode 100644 index 000000000..fd1d49df4 --- /dev/null +++ b/flow-typed/npm/box-react-ui_vx.x.x.js @@ -0,0 +1,4958 @@ +// flow-typed signature: 79c2b521d2c301fe66e46804a8581147 +// flow-typed version: <>/box-react-ui_v25.2.4/flow_v0.70.0 + +/** + * This is an autogenerated libdef stub for: + * + * 'box-react-ui' + * + * Fill this stub out by replacing all the `any` types. + * + * Once filled out, we encourage you to share your work with the + * community by sending a pull request to: + * https://github.com/flowtype/flow-typed + */ + +declare module 'box-react-ui' { + declare module.exports: any; +} + +/** + * We include stubs for each file inside this npm package in case you need to + * require those files directly. Feel free to delete any files that aren't + * needed. + */ +declare module 'box-react-ui/i18n/bn-IN' { + declare module.exports: any; +} + +declare module 'box-react-ui/i18n/da-DK' { + declare module.exports: any; +} + +declare module 'box-react-ui/i18n/de-DE' { + declare module.exports: any; +} + +declare module 'box-react-ui/i18n/en-AU' { + declare module.exports: any; +} + +declare module 'box-react-ui/i18n/en-CA' { + declare module.exports: any; +} + +declare module 'box-react-ui/i18n/en-GB' { + declare module.exports: any; +} + +declare module 'box-react-ui/i18n/en-US' { + declare module.exports: any; +} + +declare module 'box-react-ui/i18n/en-x-pseudo' { + declare module.exports: any; +} + +declare module 'box-react-ui/i18n/es-419' { + declare module.exports: any; +} + +declare module 'box-react-ui/i18n/es-ES' { + declare module.exports: any; +} + +declare module 'box-react-ui/i18n/fi-FI' { + declare module.exports: any; +} + +declare module 'box-react-ui/i18n/fr-CA' { + declare module.exports: any; +} + +declare module 'box-react-ui/i18n/fr-FR' { + declare module.exports: any; +} + +declare module 'box-react-ui/i18n/hi-IN' { + declare module.exports: any; +} + +declare module 'box-react-ui/i18n/it-IT' { + declare module.exports: any; +} + +declare module 'box-react-ui/i18n/ja-JP' { + declare module.exports: any; +} + +declare module 'box-react-ui/i18n/ko-KR' { + declare module.exports: any; +} + +declare module 'box-react-ui/i18n/nb-NO' { + declare module.exports: any; +} + +declare module 'box-react-ui/i18n/nl-NL' { + declare module.exports: any; +} + +declare module 'box-react-ui/i18n/pl-PL' { + declare module.exports: any; +} + +declare module 'box-react-ui/i18n/pt-BR' { + declare module.exports: any; +} + +declare module 'box-react-ui/i18n/ru-RU' { + declare module.exports: any; +} + +declare module 'box-react-ui/i18n/sv-SE' { + declare module.exports: any; +} + +declare module 'box-react-ui/i18n/tr-TR' { + declare module.exports: any; +} + +declare module 'box-react-ui/i18n/zh-CN' { + declare module.exports: any; +} + +declare module 'box-react-ui/i18n/zh-TW' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/build-utils/buildTranslations' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/common/box-proptypes' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/common/keyboard-events' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/common/messages' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/common/variables' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/avatar/Avatar' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/avatar/AvatarImage' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/avatar/AvatarInitials' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/avatar/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/badge/Badge' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/badge/BetaBadge' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/badge/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/badge/messages' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/badge/UpgradeBadge' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/breadcrumb/Breadcrumb' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/breadcrumb/Crumb' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/breadcrumb/EllipsisCrumb' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/breadcrumb/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/button-group/__test__/ButtonGroup-test' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/button-group/ButtonGroup' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/button-group/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/button/Button' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/button/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/checkbox/Checkbox' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/checkbox/CheckboxTooltip' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/checkbox/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/collapsible/Collapsible' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/collapsible/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/contact-datalist-item/ContactDatalistItem' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/contact-datalist-item/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/context-menu/ContextMenu' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/context-menu/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/datalist-item/DatalistItem' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/datalist-item/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/date-picker/DatePicker' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/date-picker/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/draft-js-editor/DraftJSEditor' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/draft-js-editor/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/dropdown-menu/DropdownMenu' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/dropdown-menu/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/dropdown-menu/MenuToggle' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/error-mask/ErrorMask' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/error-mask/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/fieldset/Fieldset' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/fieldset/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/flyout/Flyout' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/flyout/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/flyout/Overlay' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/focus-trap/FocusTrap' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/focus-trap/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/form-elements/draft-js-mention-selector/DraftJSMentionSelector' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/form-elements/draft-js-mention-selector/DraftJSMentionSelectorCore' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/form-elements/draft-js-mention-selector/DraftMentionDecorator' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/form-elements/draft-js-mention-selector/DraftMentionItem' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/form-elements/draft-js-mention-selector/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/form-elements/draft-js-mention-selector/messages' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/form-elements/form/Form' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/form-elements/form/FormInput' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/form-elements/form/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/form-elements/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/form-elements/input-messages' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/form-elements/text-area/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/form-elements/text-area/TextArea' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/form-elements/text-input/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/form-elements/text-input/TextInput' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/header/Header' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/header/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/hotkeys/HotkeyFriendlyModal' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/hotkeys/HotkeyFriendlyOverlay' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/hotkeys/HotkeyHelpModal' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/hotkeys/HotkeyLayer' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/hotkeys/HotkeyManager' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/hotkeys/HotkeyRecord' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/hotkeys/Hotkeys' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/hotkeys/HotkeyService' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/hotkeys/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/hotkeys/messages' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/inline-error/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/inline-error/InlineError' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/inline-notice/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/inline-notice/InlineNotice' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/label/HiddenLabel' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/label/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/label/InfoIconWithTooltip' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/label/Label' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/label/LabelPrimitive' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/label/StandardLabel' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/link/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/link/Link' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/link/LinkBase' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/link/LinkButton' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/link/LinkGroup' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/link/LinkPrimaryButton' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/loading-indicator/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/loading-indicator/LoadingIndicator' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/loading-indicator/LoadingIndicatorWrapper' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/loading-indicator/makeLoadable' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/logo/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/logo/Logo' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/menu/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/menu/Menu' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/menu/MenuItem' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/menu/MenuLinkItem' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/menu/MenuSectionHeader' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/menu/MenuSeparator' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/menu/SelectMenuItem' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/menu/SelectMenuLinkItem' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/menu/SubmenuItem' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/modal/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/modal/Modal' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/modal/ModalActions' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/modal/ModalDialog' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/nav-sidebar/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/nav-sidebar/NavList' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/nav-sidebar/NavListCollapseHeader' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/nav-sidebar/NavSidebar' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/notification/constants' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/notification/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/notification/Notification' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/notification/NotificationsWrapper' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/pill-cloud/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/pill-cloud/PillCloud' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/pill-selector-dropdown/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/pill-selector-dropdown/Pill' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/pill-selector-dropdown/PillSelector' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/pill-selector-dropdown/PillSelectorDropdown' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/plain-button/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/plain-button/PlainButton' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/portal/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/portal/Portal' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/primary-button/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/primary-button/PrimaryButton' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/progress-bar/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/progress-bar/ProgressBar' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/radio/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/radio/RadioButton' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/radio/RadioGroup' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/react-virtualized-helpers/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/react-virtualized-helpers/withInfiniteLoader' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/scroll-wrapper/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/scroll-wrapper/ScrollWrapper' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/search-form/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/search-form/SearchForm' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/section/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/section/Section' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/select-button/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/select-button/SelectButton' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/select-field/BaseSelectField' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/select-field/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/select-field/MultiSelectField' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/select-field/props' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/select-field/SingleSelectField' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/select/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/select/Select' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/selector-dropdown/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/selector-dropdown/SelectorDropdown' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/slide-carousel/CarouselHeader' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/slide-carousel/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/slide-carousel/Slide' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/slide-carousel/SlideButton' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/slide-carousel/SlideCarousel' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/slide-carousel/SlideCarouselPrimitive' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/slide-carousel/SlideNavigator' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/slide-carousel/SlidePanels' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/tab-view/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/tab-view/Tab' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/tab-view/TabView' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/tab-view/TabViewPrimitive' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/table/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/table/makeSelectable' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/table/messages' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/table/shiftSelect' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/table/Table' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/table/TableBody' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/table/TableCell' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/table/TableHeader' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/table/TableHeaderCell' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/table/TableRow' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/text-area/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/text-area/TextArea' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/text-input-with-copy-button/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/text-input-with-copy-button/TextInputWithCopyButton' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/text-input/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/text-input/TextInput' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/thumbnail-card/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/thumbnail-card/ThumbnailCard' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/thumbnail-card/ThumbnailCardDetails' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/thumbnail-card/ThumbnailCardThumbnail' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/time/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/time/messages' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/time/ReadableTime' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/toggle/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/toggle/Toggle' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/tooltip/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/components/tooltip/Tooltip' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/breadcrumbs/Breadcrumbs' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/breadcrumbs/Crumb' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/breadcrumbs/EllipsisCrumb' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/breadcrumbs/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/menu/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/menu/Menu' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/menu/ToggleMenu' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/overlay/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/overlay/Overlay' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/overlay/ToggleOverlay' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/pill-selector/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/pill-selector/PillSelector' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/pill/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/pill/Pill' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/search-metadata/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/search-metadata/messages' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/search-metadata/SearchMetadata' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/search-metadata/SearchMetadataDateRangeField' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/search-metadata/SearchMetadataField' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/search-metadata/SearchMetadataFilter' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/search-metadata/SearchMetadataNumericRangeField' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/search-metadata/SearchMetadataSelectField' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/search-metadata/SearchMetadataTemplateSelect' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/search-metadata/SearchMetadataTextField' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/select-multi/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/select-multi/SelectMulti' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/select-multi/SelectMultiPrimitive' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/selector-dropdown/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/selector-dropdown/SelectorDropdown' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/table/FilterableTableHeader' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/table/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/table/makeInfiniteScrollable' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/table/makeSelectable' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/table/makeTableHeaderSticky' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/table/messages' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/table/shiftSelect' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/table/SortableTableHeader' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/table/Table' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/table/TableCell' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/table/TableColumn' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/table/TableHeader' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/table/TableLoader' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/deprecated/table/TableRow' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/access-stats/AccessStats' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/access-stats/AccessStatsItem' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/access-stats/AccessStatsItemsList' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/access-stats/messages' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/activity-feed/activity-feed/ActivityFeed' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/activity-feed/activity-feed/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/activity-feed/approval-comment-form/ApprovalCommentForm' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/activity-feed/approval-comment-form/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/activity-feed/comment/Comment' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/activity-feed/comment/CommentText' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/activity-feed/comment/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/activity-feed/comment/InlineDelete' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/activity-feed/comment/InlineEdit' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/activity-feed/comment/Mention' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/activity-feed/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/activity-feed/keywords/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/activity-feed/keywords/Keywords' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/activity-feed/messages' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/activity-feed/task/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/activity-feed/task/Task' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/activity-feed/utils/formatTaggedMessage' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/activity-feed/version/CollapsedVersion' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/activity-feed/version/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/activity-feed/version/Version' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/activity-feed/version/VersionError' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/classification/ClassificationBadge' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/classification/ClassificationProperty' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/classification/messages' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/content-explorer/content-explorer-modal-container/ContentExplorerModalContainer' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/content-explorer/content-explorer-modal-container/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/content-explorer/content-explorer-modal/ContentExplorerModal' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/content-explorer/content-explorer-modal/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/content-explorer/content-explorer/ContentExplorer' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/content-explorer/content-explorer/ContentExplorerActionButtons' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/content-explorer/content-explorer/ContentExplorerBreadcrumbs' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/content-explorer/content-explorer/ContentExplorerEmptyState' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/content-explorer/content-explorer/ContentExplorerHeaderActions' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/content-explorer/content-explorer/ContentExplorerNewFolderButton' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/content-explorer/content-explorer/ContentExplorerSearch' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/content-explorer/content-explorer/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/content-explorer/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/content-explorer/item-list/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/content-explorer/item-list/ItemList' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/content-explorer/item-list/ItemListButton' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/content-explorer/item-list/ItemListIcon' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/content-explorer/item-list/ItemListLoadingPlaceholder' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/content-explorer/item-list/ItemListName' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/content-explorer/item-types' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/content-explorer/messages' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/content-explorer/modes' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/content-explorer/new-folder-modal/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/content-explorer/new-folder-modal/NewFolderModal' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/content-explorer/prop-types' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/in-app-message/create-message-form/constants' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/in-app-message/create-message-form/CreateMessageForm' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/in-app-message/create-message-form/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/in-app-message/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/in-app-message/targeting-expression-editor/constants' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/in-app-message/targeting-expression-editor/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/in-app-message/targeting-expression-editor/TargetingExpressionEditor' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/in-app-message/targeting-expression-editor/TargetingExpressionRow' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/in-app-message/targeting-rule/constants' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/in-app-message/targeting-rule/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/in-app-message/targeting-rule/RuleContextInputs' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/in-app-message/targeting-rule/RuleSelect' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/in-app-message/targeting-rule/RuleTypeSelect' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/in-app-message/targeting-rule/RuleValueInputAmong' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/in-app-message/targeting-rule/RuleValueInputEqual' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/in-app-message/targeting-rule/RuleValueInputsInRange' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/in-app-message/targeting-rule/TargetingRule' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/invite-collaborators-modal/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/invite-collaborators-modal/InviteCollaboratorsModal' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/invite-collaborators-modal/messages' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/invite-collaborators-modal/PermissionFlyout' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/item-details/EditableDescription' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/item-details/EditableURL' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/item-details/ItemExpirationNotice' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/item-details/ItemProperties' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/item-details/messages' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/item-details/ReadonlyDescription' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/item-details/RetentionPolicy' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/item-details/SharedLinkExpirationNotice' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/item-details/VersionHistoryLink' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/left-sidebar/Callout' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/left-sidebar/CopyrightFooter' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/left-sidebar/icons/IconAdminConsole' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/left-sidebar/icons/IconAllFiles' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/left-sidebar/icons/IconDevConsole' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/left-sidebar/icons/IconFavorites' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/left-sidebar/icons/IconFeed' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/left-sidebar/icons/IconNotes' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/left-sidebar/icons/IconNotifications' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/left-sidebar/icons/IconOwnedByMe' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/left-sidebar/icons/IconRecents' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/left-sidebar/icons/IconRelay' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/left-sidebar/icons/IconReturnToAdminConsole' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/left-sidebar/icons/IconSharedWithMe' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/left-sidebar/icons/IconSynced' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/left-sidebar/icons/IconTrash' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/left-sidebar/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/left-sidebar/InstantLogin' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/left-sidebar/LeftSidebar' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/left-sidebar/LeftSidebarDropWrapper' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/left-sidebar/LeftSidebarIconWrapper' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/left-sidebar/LeftSidebarLink' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/left-sidebar/LeftSidebarLinkCallout' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/left-sidebar/NewItemsIndicator' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/left-sidebar/RemoveButton' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/metadata-instance-editor/CascadePolicy' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/metadata-instance-editor/constants' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/metadata-instance-editor/CustomInstance' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/metadata-instance-editor/CustomInstanceNewField' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/metadata-instance-editor/EmptyContent' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/metadata-instance-editor/fields/CustomField' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/metadata-instance-editor/fields/DateField' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/metadata-instance-editor/fields/EnumField' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/metadata-instance-editor/fields/Field' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/metadata-instance-editor/fields/FloatField' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/metadata-instance-editor/fields/IntegerField' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/metadata-instance-editor/fields/MultiSelectField' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/metadata-instance-editor/fields/ReadOnlyField' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/metadata-instance-editor/fields/TextField' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/metadata-instance-editor/fields/validateField' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/metadata-instance-editor/flowTypes' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/metadata-instance-editor/Footer' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/metadata-instance-editor/Header' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/metadata-instance-editor/Instance' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/metadata-instance-editor/messages' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/metadata-instance-editor/MetadataInstanceConfirmDialog' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/metadata-instance-editor/MetadataInstanceEditor' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/metadata-instance-editor/TemplatedInstance' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/metadata-instance-editor/TemplateDropdown' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/presence/constants' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/presence/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/presence/messages' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/presence/Presence' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/presence/PresenceAvatar' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/presence/PresenceDropdown' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/presence/PresenceLink' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/presence/propTypes' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/presence/utils/presenceUtils' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/quick-search/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/quick-search/messages' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/quick-search/QuickSearch' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/quick-search/QuickSearchItem' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/quick-search/QuickSearchMessage' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/quick-search/QuickSearchSelector' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/security-cloud-game/DragCloud' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/security-cloud-game/DropCloud' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/security-cloud-game/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/security-cloud-game/messages' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/security-cloud-game/SecurityCloudGame' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/share/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/share/messages' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/share/ShareMenu' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/shared-link-modal/AccessDescription' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/shared-link-modal/AccessLabel' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/shared-link-modal/AccessMenu' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/shared-link-modal/constants' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/shared-link-modal/EmailSharedLink' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/shared-link-modal/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/shared-link-modal/messages' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/shared-link-modal/PermissionMenu' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/shared-link-modal/propTypes' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/shared-link-modal/RemoveLinkConfirmModal' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/shared-link-modal/SharedLink' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/shared-link-modal/SharedLinkAccess' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/shared-link-modal/SharedLinkModal' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/shared-link-settings-modal/AllowDownloadSection' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/shared-link-settings-modal/ExpirationSection' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/shared-link-settings-modal/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/shared-link-settings-modal/messages' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/shared-link-settings-modal/PasswordSection' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/shared-link-settings-modal/SharedLinkSettingsModal' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/shared-link-settings-modal/VanityNameSection' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/unified-share-modal/AccessDescription' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/unified-share-modal/AccessLabel' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/unified-share-modal/AccessMenu' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/unified-share-modal/constants' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/unified-share-modal/flowTypes' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/unified-share-modal/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/unified-share-modal/InviteePermissionsMenu' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/unified-share-modal/messages' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/unified-share-modal/PermissionMenu' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/unified-share-modal/RemoveLinkConfirmModal' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/unified-share-modal/SharedLink' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/unified-share-modal/SharedLinkAccess' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/unified-share-modal/UnifiedShareModal' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/version-history-modal/constants' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/version-history-modal/FileVersionActions' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/version-history-modal/FileVersionInfo' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/version-history-modal/FileVersionList' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/version-history-modal/FileVersionListItem' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/version-history-modal/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/version-history-modal/messages' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/version-history-modal/prop-types' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/features/version-history-modal/VersionHistoryModal' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/accessible-svg/AccessibleSVG' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/accessible-svg/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/adobe-sign/IconAdobeSign' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/avatars/UnknownUserAvatar' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/badges/CoauthoringBadge' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/badges/CollaborationBadge' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/badges/ExpirationBadge' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/badges/InfoBadge' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/badges/LockBadge' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/badges/QuarantineBadge' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/badges/SharedLinkBadge' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/bookmark-icon/BookmarkIcon' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/bookmark-icon/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/box-notes/IconBoxNotes' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/box-tools/IconBoxToolsDownload' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/box-tools/IconBoxToolsInstall' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/box-tools/IconBoxToolsUpgradeBrowser' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/file-icon/FileIcon' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/file-icon/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/file/IconFileAudio' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/file/IconFileBoxNote' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/file/IconFileCode' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/file/IconFileDefault' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/file/IconFileDocument' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/file/IconFileExcelSpreadsheet' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/file/IconFileGoogleDocs' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/file/IconFileGoogleSheets' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/file/IconFileGoogleSlides' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/file/IconFileIllustrator' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/file/IconFileImage' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/file/IconFileIndesign' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/file/IconFileKeynote' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/file/IconFileNumbers' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/file/IconFilePages' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/file/IconFilePDF' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/file/IconFilePhotoshop' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/file/IconFilePowerpointPresentation' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/file/IconFilePresentation' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/file/IconFileSpreadsheet' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/file/IconFileText' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/file/IconFileThreeD' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/file/IconFileVector' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/file/IconFileVideo' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/file/IconFileWordDocument' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/file/IconFileZip' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/folder-icon/FolderIcon' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/folder-icon/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/folder/IconFolderCollab' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/folder/IconFolderExternal' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/folder/IconFolderPersonal' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/folder/IconSmallFolder' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconAdd' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconAddMetadataEmptyState' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconAddTags' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconAddThin' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconAdvancedFilters' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconAlert' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconAlertCircle' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconAlignLeft' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconAllFiles' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconApps' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconAutomation' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconBarGraph' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconBell' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconBell2' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconBilling' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconBox3DCenter' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconBreadcrumbArrow' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconCalendar' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconCaretDown' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconChat' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconChatRound' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconCheck' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconChevron' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconClear' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconClock' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconClockPast' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconClose' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconCloud' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconCodeBlock' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconCollaboration' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconCollaborators' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconCollaboratorsRestricted' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconCollapse' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconComment' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconCommentsBadge' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconComposeNote' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconConePopper' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconCopy' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconCreditCardAmex' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconCreditCardDiscover' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconCreditCardJCB' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconCreditCardMasterCard' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconCreditCardVisa' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconDocIllustration' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconDocInfo' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconDownload' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconDownloadFile' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconDownloadSolid' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconEdit' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconEllipsis' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconExpand' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconExpiration' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconExpirationBadge' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconExpirationInverted' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconEye' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconEyeInverted' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconFeed' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconFlag' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconForward' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconGiftWithWings' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconGlobe' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconGraduationHat' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconGridView' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconHamburger' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconHelp' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconHome' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconInfo' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconInfoInverted' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconInformation' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconInfoThin' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconInviteCollaborators' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconLeftArrow' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconLink' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconListView' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconLock' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconLogo' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconMagicWand' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconMail' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconMaximize' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconMetadata' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconMetadataColored' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconMetadataThick' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconMinus' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconMinusThin' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconMoveCopy' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconNavigateLeft' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconNavigateRight' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconOpenWith' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconPageBack' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconPageForward' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconPencil' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconPencilSolid' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconPhone' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconPlus' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconPlusThin' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconPrint' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconPrintInverted' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconRecentFiles' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconRemove' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconRename' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconReports' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconRetention' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconRetry' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconSadCloud' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconSearch' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconSetting' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconSettingInverted' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconShare' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconSharedLink' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconSharedLinkRestricted' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconShield' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconShield2' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconSidebar' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconSidebarLeft' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconSmallClose' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconSort' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconSortChevron' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconStar' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconSync' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconTag' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconThumbsUp' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconToolbox' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconTrackNext' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconTrackPrevious' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconTrash' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconTrophyCup' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconTrophyCupWithTooltip' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconUnlock' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconUnsync' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconUpdated' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconUpgradeCloud' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconUpload' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconUploadCloud' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconUploadSolid' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconVerified' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/general/IconWatermark' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/google-docs/GoogleDocsIcon' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/google-docs/IconGoogleDocs' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/google-docs/IconGoogleSheets' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/google-docs/IconGoogleSlides' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/item-icon/index' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/item-icon/ItemIcon' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/iwork/IconIWorkKeynote' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/iwork/IconIWorkKeynoteDesktop' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/iwork/IconIWorkNumbers' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/iwork/IconIWorkNumbersDesktop' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/iwork/IconIWorkPages' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/iwork/IconIWorkPagesDesktop' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/iwork/IconIWorkTrio' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/iwork/IWorkDesktopIcon' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/iwork/IWorkIcon' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/microsoft-office/IconExcelDesktop' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/microsoft-office/IconExcelOnline' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/microsoft-office/IconOfficeWordmark' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/microsoft-office/IconPowerPointDesktop' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/microsoft-office/IconPowerPointOnline' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/microsoft-office/IconWordDesktop' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/microsoft-office/IconWordOnline' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/microsoft-office/OfficeDesktopIcon' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/microsoft-office/OfficeOnlineIcon' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/promotions/IconMobileApp' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/promotions/IconNotesLogo' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/promotions/IconSync' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/states/AccessStatsEmptyState' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/states/ActivityFeedEmptyState' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/states/CollaboratorsEmptyState' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/states/CollectionSidebarEmptyState' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/states/CongratsPartyPeopleState' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/states/EnvelopeTrophyState' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/states/ErrorEmptyState' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/states/FavoritesEmptyState' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/states/FeedEmptyState' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/states/FolderEmptyState' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/states/MultiSelectState' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/states/RecentsEmptyState' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/states/SearchEmptyState' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/states/SelectedItemsEmptyState' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/states/SetDefaultAppState' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/states/SharedLinkErrorState' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/states/SyncEmptyState' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/states/TrashEmptyState' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/states/UpdatesEmptyState' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/states/UploadEmptyState' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/states/UploadFilePaywallState' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/states/UploadStartState' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/icons/states/UploadSuccessState' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/styles/variables' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/utils/datetime' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/utils/getFileSize' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/utils/keys' { + declare module.exports: any; +} + +declare module 'box-react-ui/lib/utils/parseCSV' { + declare module.exports: any; +} + +// Filename aliases +declare module 'box-react-ui/i18n/bn-IN.js' { + declare module.exports: $Exports<'box-react-ui/i18n/bn-IN'>; +} +declare module 'box-react-ui/i18n/da-DK.js' { + declare module.exports: $Exports<'box-react-ui/i18n/da-DK'>; +} +declare module 'box-react-ui/i18n/de-DE.js' { + declare module.exports: $Exports<'box-react-ui/i18n/de-DE'>; +} +declare module 'box-react-ui/i18n/en-AU.js' { + declare module.exports: $Exports<'box-react-ui/i18n/en-AU'>; +} +declare module 'box-react-ui/i18n/en-CA.js' { + declare module.exports: $Exports<'box-react-ui/i18n/en-CA'>; +} +declare module 'box-react-ui/i18n/en-GB.js' { + declare module.exports: $Exports<'box-react-ui/i18n/en-GB'>; +} +declare module 'box-react-ui/i18n/en-US.js' { + declare module.exports: $Exports<'box-react-ui/i18n/en-US'>; +} +declare module 'box-react-ui/i18n/en-x-pseudo.js' { + declare module.exports: $Exports<'box-react-ui/i18n/en-x-pseudo'>; +} +declare module 'box-react-ui/i18n/es-419.js' { + declare module.exports: $Exports<'box-react-ui/i18n/es-419'>; +} +declare module 'box-react-ui/i18n/es-ES.js' { + declare module.exports: $Exports<'box-react-ui/i18n/es-ES'>; +} +declare module 'box-react-ui/i18n/fi-FI.js' { + declare module.exports: $Exports<'box-react-ui/i18n/fi-FI'>; +} +declare module 'box-react-ui/i18n/fr-CA.js' { + declare module.exports: $Exports<'box-react-ui/i18n/fr-CA'>; +} +declare module 'box-react-ui/i18n/fr-FR.js' { + declare module.exports: $Exports<'box-react-ui/i18n/fr-FR'>; +} +declare module 'box-react-ui/i18n/hi-IN.js' { + declare module.exports: $Exports<'box-react-ui/i18n/hi-IN'>; +} +declare module 'box-react-ui/i18n/it-IT.js' { + declare module.exports: $Exports<'box-react-ui/i18n/it-IT'>; +} +declare module 'box-react-ui/i18n/ja-JP.js' { + declare module.exports: $Exports<'box-react-ui/i18n/ja-JP'>; +} +declare module 'box-react-ui/i18n/ko-KR.js' { + declare module.exports: $Exports<'box-react-ui/i18n/ko-KR'>; +} +declare module 'box-react-ui/i18n/nb-NO.js' { + declare module.exports: $Exports<'box-react-ui/i18n/nb-NO'>; +} +declare module 'box-react-ui/i18n/nl-NL.js' { + declare module.exports: $Exports<'box-react-ui/i18n/nl-NL'>; +} +declare module 'box-react-ui/i18n/pl-PL.js' { + declare module.exports: $Exports<'box-react-ui/i18n/pl-PL'>; +} +declare module 'box-react-ui/i18n/pt-BR.js' { + declare module.exports: $Exports<'box-react-ui/i18n/pt-BR'>; +} +declare module 'box-react-ui/i18n/ru-RU.js' { + declare module.exports: $Exports<'box-react-ui/i18n/ru-RU'>; +} +declare module 'box-react-ui/i18n/sv-SE.js' { + declare module.exports: $Exports<'box-react-ui/i18n/sv-SE'>; +} +declare module 'box-react-ui/i18n/tr-TR.js' { + declare module.exports: $Exports<'box-react-ui/i18n/tr-TR'>; +} +declare module 'box-react-ui/i18n/zh-CN.js' { + declare module.exports: $Exports<'box-react-ui/i18n/zh-CN'>; +} +declare module 'box-react-ui/i18n/zh-TW.js' { + declare module.exports: $Exports<'box-react-ui/i18n/zh-TW'>; +} +declare module 'box-react-ui/lib/build-utils/buildTranslations.js' { + declare module.exports: $Exports<'box-react-ui/lib/build-utils/buildTranslations'>; +} +declare module 'box-react-ui/lib/common/box-proptypes.js' { + declare module.exports: $Exports<'box-react-ui/lib/common/box-proptypes'>; +} +declare module 'box-react-ui/lib/common/keyboard-events.js' { + declare module.exports: $Exports<'box-react-ui/lib/common/keyboard-events'>; +} +declare module 'box-react-ui/lib/common/messages.js' { + declare module.exports: $Exports<'box-react-ui/lib/common/messages'>; +} +declare module 'box-react-ui/lib/common/variables.js' { + declare module.exports: $Exports<'box-react-ui/lib/common/variables'>; +} +declare module 'box-react-ui/lib/components/avatar/Avatar.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/avatar/Avatar'>; +} +declare module 'box-react-ui/lib/components/avatar/AvatarImage.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/avatar/AvatarImage'>; +} +declare module 'box-react-ui/lib/components/avatar/AvatarInitials.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/avatar/AvatarInitials'>; +} +declare module 'box-react-ui/lib/components/avatar' { + declare module.exports: $Exports<'box-react-ui/lib/components/avatar/index'>; +} +declare module 'box-react-ui/lib/components/badge/Badge.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/badge/Badge'>; +} +declare module 'box-react-ui/lib/components/badge/BetaBadge.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/badge/BetaBadge'>; +} +declare module 'box-react-ui/lib/components/badge' { + declare module.exports: $Exports<'box-react-ui/lib/components/badge/index'>; +} +declare module 'box-react-ui/lib/components/badge/messages.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/badge/messages'>; +} +declare module 'box-react-ui/lib/components/badge/UpgradeBadge.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/badge/UpgradeBadge'>; +} +declare module 'box-react-ui/lib/components/breadcrumb/Breadcrumb.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/breadcrumb/Breadcrumb'>; +} +declare module 'box-react-ui/lib/components/breadcrumb/Crumb.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/breadcrumb/Crumb'>; +} +declare module 'box-react-ui/lib/components/breadcrumb/EllipsisCrumb.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/breadcrumb/EllipsisCrumb'>; +} +declare module 'box-react-ui/lib/components/breadcrumb' { + declare module.exports: $Exports<'box-react-ui/lib/components/breadcrumb/index'>; +} +declare module 'box-react-ui/lib/components/button-group/__test__/ButtonGroup-test.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/button-group/__test__/ButtonGroup-test'>; +} +declare module 'box-react-ui/lib/components/button-group/ButtonGroup.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/button-group/ButtonGroup'>; +} +declare module 'box-react-ui/lib/components/button-group' { + declare module.exports: $Exports<'box-react-ui/lib/components/button-group/index'>; +} +declare module 'box-react-ui/lib/components/button/Button.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/button/Button'>; +} +declare module 'box-react-ui/lib/components/button' { + declare module.exports: $Exports<'box-react-ui/lib/components/button/index'>; +} +declare module 'box-react-ui/lib/components/checkbox/Checkbox.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/checkbox/Checkbox'>; +} +declare module 'box-react-ui/lib/components/checkbox/CheckboxTooltip.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/checkbox/CheckboxTooltip'>; +} +declare module 'box-react-ui/lib/components/checkbox' { + declare module.exports: $Exports<'box-react-ui/lib/components/checkbox/index'>; +} +declare module 'box-react-ui/lib/components/collapsible/Collapsible.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/collapsible/Collapsible'>; +} +declare module 'box-react-ui/lib/components/collapsible' { + declare module.exports: $Exports<'box-react-ui/lib/components/collapsible/index'>; +} +declare module 'box-react-ui/lib/components/contact-datalist-item/ContactDatalistItem.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/contact-datalist-item/ContactDatalistItem'>; +} +declare module 'box-react-ui/lib/components/contact-datalist-item' { + declare module.exports: $Exports<'box-react-ui/lib/components/contact-datalist-item/index'>; +} +declare module 'box-react-ui/lib/components/context-menu/ContextMenu.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/context-menu/ContextMenu'>; +} +declare module 'box-react-ui/lib/components/context-menu' { + declare module.exports: $Exports<'box-react-ui/lib/components/context-menu/index'>; +} +declare module 'box-react-ui/lib/components/datalist-item/DatalistItem.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/datalist-item/DatalistItem'>; +} +declare module 'box-react-ui/lib/components/datalist-item' { + declare module.exports: $Exports<'box-react-ui/lib/components/datalist-item/index'>; +} +declare module 'box-react-ui/lib/components/date-picker/DatePicker.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/date-picker/DatePicker'>; +} +declare module 'box-react-ui/lib/components/date-picker' { + declare module.exports: $Exports<'box-react-ui/lib/components/date-picker/index'>; +} +declare module 'box-react-ui/lib/components/draft-js-editor/DraftJSEditor.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/draft-js-editor/DraftJSEditor'>; +} +declare module 'box-react-ui/lib/components/draft-js-editor' { + declare module.exports: $Exports<'box-react-ui/lib/components/draft-js-editor/index'>; +} +declare module 'box-react-ui/lib/components/dropdown-menu/DropdownMenu.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/dropdown-menu/DropdownMenu'>; +} +declare module 'box-react-ui/lib/components/dropdown-menu' { + declare module.exports: $Exports<'box-react-ui/lib/components/dropdown-menu/index'>; +} +declare module 'box-react-ui/lib/components/dropdown-menu/MenuToggle.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/dropdown-menu/MenuToggle'>; +} +declare module 'box-react-ui/lib/components/error-mask/ErrorMask.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/error-mask/ErrorMask'>; +} +declare module 'box-react-ui/lib/components/error-mask' { + declare module.exports: $Exports<'box-react-ui/lib/components/error-mask/index'>; +} +declare module 'box-react-ui/lib/components/fieldset/Fieldset.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/fieldset/Fieldset'>; +} +declare module 'box-react-ui/lib/components/fieldset' { + declare module.exports: $Exports<'box-react-ui/lib/components/fieldset/index'>; +} +declare module 'box-react-ui/lib/components/flyout/Flyout.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/flyout/Flyout'>; +} +declare module 'box-react-ui/lib/components/flyout' { + declare module.exports: $Exports<'box-react-ui/lib/components/flyout/index'>; +} +declare module 'box-react-ui/lib/components/flyout/Overlay.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/flyout/Overlay'>; +} +declare module 'box-react-ui/lib/components/focus-trap/FocusTrap.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/focus-trap/FocusTrap'>; +} +declare module 'box-react-ui/lib/components/focus-trap' { + declare module.exports: $Exports<'box-react-ui/lib/components/focus-trap/index'>; +} +declare module 'box-react-ui/lib/components/form-elements/draft-js-mention-selector/DraftJSMentionSelector.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/form-elements/draft-js-mention-selector/DraftJSMentionSelector'>; +} +declare module 'box-react-ui/lib/components/form-elements/draft-js-mention-selector/DraftJSMentionSelectorCore.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/form-elements/draft-js-mention-selector/DraftJSMentionSelectorCore'>; +} +declare module 'box-react-ui/lib/components/form-elements/draft-js-mention-selector/DraftMentionDecorator.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/form-elements/draft-js-mention-selector/DraftMentionDecorator'>; +} +declare module 'box-react-ui/lib/components/form-elements/draft-js-mention-selector/DraftMentionItem.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/form-elements/draft-js-mention-selector/DraftMentionItem'>; +} +declare module 'box-react-ui/lib/components/form-elements/draft-js-mention-selector' { + declare module.exports: $Exports<'box-react-ui/lib/components/form-elements/draft-js-mention-selector/index'>; +} +declare module 'box-react-ui/lib/components/form-elements/draft-js-mention-selector/messages.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/form-elements/draft-js-mention-selector/messages'>; +} +declare module 'box-react-ui/lib/components/form-elements/form/Form.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/form-elements/form/Form'>; +} +declare module 'box-react-ui/lib/components/form-elements/form/FormInput.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/form-elements/form/FormInput'>; +} +declare module 'box-react-ui/lib/components/form-elements/form' { + declare module.exports: $Exports<'box-react-ui/lib/components/form-elements/form/index'>; +} +declare module 'box-react-ui/lib/components/form-elements' { + declare module.exports: $Exports<'box-react-ui/lib/components/form-elements/index'>; +} +declare module 'box-react-ui/lib/components/form-elements/input-messages.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/form-elements/input-messages'>; +} +declare module 'box-react-ui/lib/components/form-elements/text-area' { + declare module.exports: $Exports<'box-react-ui/lib/components/form-elements/text-area/index'>; +} +declare module 'box-react-ui/lib/components/form-elements/text-area/TextArea.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/form-elements/text-area/TextArea'>; +} +declare module 'box-react-ui/lib/components/form-elements/text-input' { + declare module.exports: $Exports<'box-react-ui/lib/components/form-elements/text-input/index'>; +} +declare module 'box-react-ui/lib/components/form-elements/text-input/TextInput.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/form-elements/text-input/TextInput'>; +} +declare module 'box-react-ui/lib/components/header/Header.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/header/Header'>; +} +declare module 'box-react-ui/lib/components/header' { + declare module.exports: $Exports<'box-react-ui/lib/components/header/index'>; +} +declare module 'box-react-ui/lib/components/hotkeys/HotkeyFriendlyModal.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/hotkeys/HotkeyFriendlyModal'>; +} +declare module 'box-react-ui/lib/components/hotkeys/HotkeyFriendlyOverlay.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/hotkeys/HotkeyFriendlyOverlay'>; +} +declare module 'box-react-ui/lib/components/hotkeys/HotkeyHelpModal.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/hotkeys/HotkeyHelpModal'>; +} +declare module 'box-react-ui/lib/components/hotkeys/HotkeyLayer.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/hotkeys/HotkeyLayer'>; +} +declare module 'box-react-ui/lib/components/hotkeys/HotkeyManager.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/hotkeys/HotkeyManager'>; +} +declare module 'box-react-ui/lib/components/hotkeys/HotkeyRecord.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/hotkeys/HotkeyRecord'>; +} +declare module 'box-react-ui/lib/components/hotkeys/Hotkeys.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/hotkeys/Hotkeys'>; +} +declare module 'box-react-ui/lib/components/hotkeys/HotkeyService.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/hotkeys/HotkeyService'>; +} +declare module 'box-react-ui/lib/components/hotkeys' { + declare module.exports: $Exports<'box-react-ui/lib/components/hotkeys/index'>; +} +declare module 'box-react-ui/lib/components/hotkeys/messages.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/hotkeys/messages'>; +} +declare module 'box-react-ui/lib/components/inline-error' { + declare module.exports: $Exports<'box-react-ui/lib/components/inline-error/index'>; +} +declare module 'box-react-ui/lib/components/inline-error/InlineError.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/inline-error/InlineError'>; +} +declare module 'box-react-ui/lib/components/inline-notice' { + declare module.exports: $Exports<'box-react-ui/lib/components/inline-notice/index'>; +} +declare module 'box-react-ui/lib/components/inline-notice/InlineNotice.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/inline-notice/InlineNotice'>; +} +declare module 'box-react-ui/lib/components/label/HiddenLabel.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/label/HiddenLabel'>; +} +declare module 'box-react-ui/lib/components/label' { + declare module.exports: $Exports<'box-react-ui/lib/components/label/index'>; +} +declare module 'box-react-ui/lib/components/label/InfoIconWithTooltip.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/label/InfoIconWithTooltip'>; +} +declare module 'box-react-ui/lib/components/label/Label.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/label/Label'>; +} +declare module 'box-react-ui/lib/components/label/LabelPrimitive.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/label/LabelPrimitive'>; +} +declare module 'box-react-ui/lib/components/label/StandardLabel.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/label/StandardLabel'>; +} +declare module 'box-react-ui/lib/components/link' { + declare module.exports: $Exports<'box-react-ui/lib/components/link/index'>; +} +declare module 'box-react-ui/lib/components/link/Link.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/link/Link'>; +} +declare module 'box-react-ui/lib/components/link/LinkBase.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/link/LinkBase'>; +} +declare module 'box-react-ui/lib/components/link/LinkButton.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/link/LinkButton'>; +} +declare module 'box-react-ui/lib/components/link/LinkGroup.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/link/LinkGroup'>; +} +declare module 'box-react-ui/lib/components/link/LinkPrimaryButton.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/link/LinkPrimaryButton'>; +} +declare module 'box-react-ui/lib/components/loading-indicator' { + declare module.exports: $Exports<'box-react-ui/lib/components/loading-indicator/index'>; +} +declare module 'box-react-ui/lib/components/loading-indicator/LoadingIndicator.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/loading-indicator/LoadingIndicator'>; +} +declare module 'box-react-ui/lib/components/loading-indicator/LoadingIndicatorWrapper.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/loading-indicator/LoadingIndicatorWrapper'>; +} +declare module 'box-react-ui/lib/components/loading-indicator/makeLoadable.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/loading-indicator/makeLoadable'>; +} +declare module 'box-react-ui/lib/components/logo' { + declare module.exports: $Exports<'box-react-ui/lib/components/logo/index'>; +} +declare module 'box-react-ui/lib/components/logo/Logo.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/logo/Logo'>; +} +declare module 'box-react-ui/lib/components/menu' { + declare module.exports: $Exports<'box-react-ui/lib/components/menu/index'>; +} +declare module 'box-react-ui/lib/components/menu/Menu.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/menu/Menu'>; +} +declare module 'box-react-ui/lib/components/menu/MenuItem.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/menu/MenuItem'>; +} +declare module 'box-react-ui/lib/components/menu/MenuLinkItem.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/menu/MenuLinkItem'>; +} +declare module 'box-react-ui/lib/components/menu/MenuSectionHeader.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/menu/MenuSectionHeader'>; +} +declare module 'box-react-ui/lib/components/menu/MenuSeparator.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/menu/MenuSeparator'>; +} +declare module 'box-react-ui/lib/components/menu/SelectMenuItem.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/menu/SelectMenuItem'>; +} +declare module 'box-react-ui/lib/components/menu/SelectMenuLinkItem.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/menu/SelectMenuLinkItem'>; +} +declare module 'box-react-ui/lib/components/menu/SubmenuItem.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/menu/SubmenuItem'>; +} +declare module 'box-react-ui/lib/components/modal' { + declare module.exports: $Exports<'box-react-ui/lib/components/modal/index'>; +} +declare module 'box-react-ui/lib/components/modal/Modal.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/modal/Modal'>; +} +declare module 'box-react-ui/lib/components/modal/ModalActions.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/modal/ModalActions'>; +} +declare module 'box-react-ui/lib/components/modal/ModalDialog.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/modal/ModalDialog'>; +} +declare module 'box-react-ui/lib/components/nav-sidebar' { + declare module.exports: $Exports<'box-react-ui/lib/components/nav-sidebar/index'>; +} +declare module 'box-react-ui/lib/components/nav-sidebar/NavList.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/nav-sidebar/NavList'>; +} +declare module 'box-react-ui/lib/components/nav-sidebar/NavListCollapseHeader.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/nav-sidebar/NavListCollapseHeader'>; +} +declare module 'box-react-ui/lib/components/nav-sidebar/NavSidebar.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/nav-sidebar/NavSidebar'>; +} +declare module 'box-react-ui/lib/components/notification/constants.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/notification/constants'>; +} +declare module 'box-react-ui/lib/components/notification' { + declare module.exports: $Exports<'box-react-ui/lib/components/notification/index'>; +} +declare module 'box-react-ui/lib/components/notification/Notification.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/notification/Notification'>; +} +declare module 'box-react-ui/lib/components/notification/NotificationsWrapper.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/notification/NotificationsWrapper'>; +} +declare module 'box-react-ui/lib/components/pill-cloud' { + declare module.exports: $Exports<'box-react-ui/lib/components/pill-cloud/index'>; +} +declare module 'box-react-ui/lib/components/pill-cloud/PillCloud.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/pill-cloud/PillCloud'>; +} +declare module 'box-react-ui/lib/components/pill-selector-dropdown' { + declare module.exports: $Exports<'box-react-ui/lib/components/pill-selector-dropdown/index'>; +} +declare module 'box-react-ui/lib/components/pill-selector-dropdown/Pill.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/pill-selector-dropdown/Pill'>; +} +declare module 'box-react-ui/lib/components/pill-selector-dropdown/PillSelector.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/pill-selector-dropdown/PillSelector'>; +} +declare module 'box-react-ui/lib/components/pill-selector-dropdown/PillSelectorDropdown.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/pill-selector-dropdown/PillSelectorDropdown'>; +} +declare module 'box-react-ui/lib/components/plain-button' { + declare module.exports: $Exports<'box-react-ui/lib/components/plain-button/index'>; +} +declare module 'box-react-ui/lib/components/plain-button/PlainButton.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/plain-button/PlainButton'>; +} +declare module 'box-react-ui/lib/components/portal' { + declare module.exports: $Exports<'box-react-ui/lib/components/portal/index'>; +} +declare module 'box-react-ui/lib/components/portal/Portal.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/portal/Portal'>; +} +declare module 'box-react-ui/lib/components/primary-button' { + declare module.exports: $Exports<'box-react-ui/lib/components/primary-button/index'>; +} +declare module 'box-react-ui/lib/components/primary-button/PrimaryButton.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/primary-button/PrimaryButton'>; +} +declare module 'box-react-ui/lib/components/progress-bar' { + declare module.exports: $Exports<'box-react-ui/lib/components/progress-bar/index'>; +} +declare module 'box-react-ui/lib/components/progress-bar/ProgressBar.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/progress-bar/ProgressBar'>; +} +declare module 'box-react-ui/lib/components/radio' { + declare module.exports: $Exports<'box-react-ui/lib/components/radio/index'>; +} +declare module 'box-react-ui/lib/components/radio/RadioButton.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/radio/RadioButton'>; +} +declare module 'box-react-ui/lib/components/radio/RadioGroup.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/radio/RadioGroup'>; +} +declare module 'box-react-ui/lib/components/react-virtualized-helpers' { + declare module.exports: $Exports<'box-react-ui/lib/components/react-virtualized-helpers/index'>; +} +declare module 'box-react-ui/lib/components/react-virtualized-helpers/withInfiniteLoader.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/react-virtualized-helpers/withInfiniteLoader'>; +} +declare module 'box-react-ui/lib/components/scroll-wrapper' { + declare module.exports: $Exports<'box-react-ui/lib/components/scroll-wrapper/index'>; +} +declare module 'box-react-ui/lib/components/scroll-wrapper/ScrollWrapper.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/scroll-wrapper/ScrollWrapper'>; +} +declare module 'box-react-ui/lib/components/search-form' { + declare module.exports: $Exports<'box-react-ui/lib/components/search-form/index'>; +} +declare module 'box-react-ui/lib/components/search-form/SearchForm.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/search-form/SearchForm'>; +} +declare module 'box-react-ui/lib/components/section' { + declare module.exports: $Exports<'box-react-ui/lib/components/section/index'>; +} +declare module 'box-react-ui/lib/components/section/Section.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/section/Section'>; +} +declare module 'box-react-ui/lib/components/select-button' { + declare module.exports: $Exports<'box-react-ui/lib/components/select-button/index'>; +} +declare module 'box-react-ui/lib/components/select-button/SelectButton.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/select-button/SelectButton'>; +} +declare module 'box-react-ui/lib/components/select-field/BaseSelectField.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/select-field/BaseSelectField'>; +} +declare module 'box-react-ui/lib/components/select-field' { + declare module.exports: $Exports<'box-react-ui/lib/components/select-field/index'>; +} +declare module 'box-react-ui/lib/components/select-field/MultiSelectField.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/select-field/MultiSelectField'>; +} +declare module 'box-react-ui/lib/components/select-field/props.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/select-field/props'>; +} +declare module 'box-react-ui/lib/components/select-field/SingleSelectField.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/select-field/SingleSelectField'>; +} +declare module 'box-react-ui/lib/components/select' { + declare module.exports: $Exports<'box-react-ui/lib/components/select/index'>; +} +declare module 'box-react-ui/lib/components/select/Select.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/select/Select'>; +} +declare module 'box-react-ui/lib/components/selector-dropdown' { + declare module.exports: $Exports<'box-react-ui/lib/components/selector-dropdown/index'>; +} +declare module 'box-react-ui/lib/components/selector-dropdown/SelectorDropdown.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/selector-dropdown/SelectorDropdown'>; +} +declare module 'box-react-ui/lib/components/slide-carousel/CarouselHeader.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/slide-carousel/CarouselHeader'>; +} +declare module 'box-react-ui/lib/components/slide-carousel' { + declare module.exports: $Exports<'box-react-ui/lib/components/slide-carousel/index'>; +} +declare module 'box-react-ui/lib/components/slide-carousel/Slide.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/slide-carousel/Slide'>; +} +declare module 'box-react-ui/lib/components/slide-carousel/SlideButton.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/slide-carousel/SlideButton'>; +} +declare module 'box-react-ui/lib/components/slide-carousel/SlideCarousel.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/slide-carousel/SlideCarousel'>; +} +declare module 'box-react-ui/lib/components/slide-carousel/SlideCarouselPrimitive.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/slide-carousel/SlideCarouselPrimitive'>; +} +declare module 'box-react-ui/lib/components/slide-carousel/SlideNavigator.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/slide-carousel/SlideNavigator'>; +} +declare module 'box-react-ui/lib/components/slide-carousel/SlidePanels.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/slide-carousel/SlidePanels'>; +} +declare module 'box-react-ui/lib/components/tab-view' { + declare module.exports: $Exports<'box-react-ui/lib/components/tab-view/index'>; +} +declare module 'box-react-ui/lib/components/tab-view/Tab.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/tab-view/Tab'>; +} +declare module 'box-react-ui/lib/components/tab-view/TabView.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/tab-view/TabView'>; +} +declare module 'box-react-ui/lib/components/tab-view/TabViewPrimitive.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/tab-view/TabViewPrimitive'>; +} +declare module 'box-react-ui/lib/components/table' { + declare module.exports: $Exports<'box-react-ui/lib/components/table/index'>; +} +declare module 'box-react-ui/lib/components/table/makeSelectable.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/table/makeSelectable'>; +} +declare module 'box-react-ui/lib/components/table/messages.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/table/messages'>; +} +declare module 'box-react-ui/lib/components/table/shiftSelect.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/table/shiftSelect'>; +} +declare module 'box-react-ui/lib/components/table/Table.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/table/Table'>; +} +declare module 'box-react-ui/lib/components/table/TableBody.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/table/TableBody'>; +} +declare module 'box-react-ui/lib/components/table/TableCell.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/table/TableCell'>; +} +declare module 'box-react-ui/lib/components/table/TableHeader.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/table/TableHeader'>; +} +declare module 'box-react-ui/lib/components/table/TableHeaderCell.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/table/TableHeaderCell'>; +} +declare module 'box-react-ui/lib/components/table/TableRow.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/table/TableRow'>; +} +declare module 'box-react-ui/lib/components/text-area' { + declare module.exports: $Exports<'box-react-ui/lib/components/text-area/index'>; +} +declare module 'box-react-ui/lib/components/text-area/TextArea.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/text-area/TextArea'>; +} +declare module 'box-react-ui/lib/components/text-input-with-copy-button' { + declare module.exports: $Exports<'box-react-ui/lib/components/text-input-with-copy-button/index'>; +} +declare module 'box-react-ui/lib/components/text-input-with-copy-button/TextInputWithCopyButton.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/text-input-with-copy-button/TextInputWithCopyButton'>; +} +declare module 'box-react-ui/lib/components/text-input' { + declare module.exports: $Exports<'box-react-ui/lib/components/text-input/index'>; +} +declare module 'box-react-ui/lib/components/text-input/TextInput.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/text-input/TextInput'>; +} +declare module 'box-react-ui/lib/components/thumbnail-card' { + declare module.exports: $Exports<'box-react-ui/lib/components/thumbnail-card/index'>; +} +declare module 'box-react-ui/lib/components/thumbnail-card/ThumbnailCard.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/thumbnail-card/ThumbnailCard'>; +} +declare module 'box-react-ui/lib/components/thumbnail-card/ThumbnailCardDetails.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/thumbnail-card/ThumbnailCardDetails'>; +} +declare module 'box-react-ui/lib/components/thumbnail-card/ThumbnailCardThumbnail.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/thumbnail-card/ThumbnailCardThumbnail'>; +} +declare module 'box-react-ui/lib/components/time' { + declare module.exports: $Exports<'box-react-ui/lib/components/time/index'>; +} +declare module 'box-react-ui/lib/components/time/messages.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/time/messages'>; +} +declare module 'box-react-ui/lib/components/time/ReadableTime.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/time/ReadableTime'>; +} +declare module 'box-react-ui/lib/components/toggle' { + declare module.exports: $Exports<'box-react-ui/lib/components/toggle/index'>; +} +declare module 'box-react-ui/lib/components/toggle/Toggle.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/toggle/Toggle'>; +} +declare module 'box-react-ui/lib/components/tooltip' { + declare module.exports: $Exports<'box-react-ui/lib/components/tooltip/index'>; +} +declare module 'box-react-ui/lib/components/tooltip/Tooltip.js' { + declare module.exports: $Exports<'box-react-ui/lib/components/tooltip/Tooltip'>; +} +declare module 'box-react-ui/lib/deprecated/breadcrumbs/Breadcrumbs.js' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/breadcrumbs/Breadcrumbs'>; +} +declare module 'box-react-ui/lib/deprecated/breadcrumbs/Crumb.js' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/breadcrumbs/Crumb'>; +} +declare module 'box-react-ui/lib/deprecated/breadcrumbs/EllipsisCrumb.js' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/breadcrumbs/EllipsisCrumb'>; +} +declare module 'box-react-ui/lib/deprecated/breadcrumbs' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/breadcrumbs/index'>; +} +declare module 'box-react-ui/lib/deprecated/menu' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/menu/index'>; +} +declare module 'box-react-ui/lib/deprecated/menu/Menu.js' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/menu/Menu'>; +} +declare module 'box-react-ui/lib/deprecated/menu/ToggleMenu.js' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/menu/ToggleMenu'>; +} +declare module 'box-react-ui/lib/deprecated/overlay' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/overlay/index'>; +} +declare module 'box-react-ui/lib/deprecated/overlay/Overlay.js' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/overlay/Overlay'>; +} +declare module 'box-react-ui/lib/deprecated/overlay/ToggleOverlay.js' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/overlay/ToggleOverlay'>; +} +declare module 'box-react-ui/lib/deprecated/pill-selector' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/pill-selector/index'>; +} +declare module 'box-react-ui/lib/deprecated/pill-selector/PillSelector.js' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/pill-selector/PillSelector'>; +} +declare module 'box-react-ui/lib/deprecated/pill' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/pill/index'>; +} +declare module 'box-react-ui/lib/deprecated/pill/Pill.js' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/pill/Pill'>; +} +declare module 'box-react-ui/lib/deprecated/search-metadata' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/search-metadata/index'>; +} +declare module 'box-react-ui/lib/deprecated/search-metadata/messages.js' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/search-metadata/messages'>; +} +declare module 'box-react-ui/lib/deprecated/search-metadata/SearchMetadata.js' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/search-metadata/SearchMetadata'>; +} +declare module 'box-react-ui/lib/deprecated/search-metadata/SearchMetadataDateRangeField.js' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/search-metadata/SearchMetadataDateRangeField'>; +} +declare module 'box-react-ui/lib/deprecated/search-metadata/SearchMetadataField.js' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/search-metadata/SearchMetadataField'>; +} +declare module 'box-react-ui/lib/deprecated/search-metadata/SearchMetadataFilter.js' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/search-metadata/SearchMetadataFilter'>; +} +declare module 'box-react-ui/lib/deprecated/search-metadata/SearchMetadataNumericRangeField.js' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/search-metadata/SearchMetadataNumericRangeField'>; +} +declare module 'box-react-ui/lib/deprecated/search-metadata/SearchMetadataSelectField.js' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/search-metadata/SearchMetadataSelectField'>; +} +declare module 'box-react-ui/lib/deprecated/search-metadata/SearchMetadataTemplateSelect.js' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/search-metadata/SearchMetadataTemplateSelect'>; +} +declare module 'box-react-ui/lib/deprecated/search-metadata/SearchMetadataTextField.js' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/search-metadata/SearchMetadataTextField'>; +} +declare module 'box-react-ui/lib/deprecated/select-multi' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/select-multi/index'>; +} +declare module 'box-react-ui/lib/deprecated/select-multi/SelectMulti.js' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/select-multi/SelectMulti'>; +} +declare module 'box-react-ui/lib/deprecated/select-multi/SelectMultiPrimitive.js' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/select-multi/SelectMultiPrimitive'>; +} +declare module 'box-react-ui/lib/deprecated/selector-dropdown' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/selector-dropdown/index'>; +} +declare module 'box-react-ui/lib/deprecated/selector-dropdown/SelectorDropdown.js' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/selector-dropdown/SelectorDropdown'>; +} +declare module 'box-react-ui/lib/deprecated/table/FilterableTableHeader.js' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/table/FilterableTableHeader'>; +} +declare module 'box-react-ui/lib/deprecated/table' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/table/index'>; +} +declare module 'box-react-ui/lib/deprecated/table/makeInfiniteScrollable.js' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/table/makeInfiniteScrollable'>; +} +declare module 'box-react-ui/lib/deprecated/table/makeSelectable.js' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/table/makeSelectable'>; +} +declare module 'box-react-ui/lib/deprecated/table/makeTableHeaderSticky.js' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/table/makeTableHeaderSticky'>; +} +declare module 'box-react-ui/lib/deprecated/table/messages.js' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/table/messages'>; +} +declare module 'box-react-ui/lib/deprecated/table/shiftSelect.js' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/table/shiftSelect'>; +} +declare module 'box-react-ui/lib/deprecated/table/SortableTableHeader.js' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/table/SortableTableHeader'>; +} +declare module 'box-react-ui/lib/deprecated/table/Table.js' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/table/Table'>; +} +declare module 'box-react-ui/lib/deprecated/table/TableCell.js' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/table/TableCell'>; +} +declare module 'box-react-ui/lib/deprecated/table/TableColumn.js' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/table/TableColumn'>; +} +declare module 'box-react-ui/lib/deprecated/table/TableHeader.js' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/table/TableHeader'>; +} +declare module 'box-react-ui/lib/deprecated/table/TableLoader.js' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/table/TableLoader'>; +} +declare module 'box-react-ui/lib/deprecated/table/TableRow.js' { + declare module.exports: $Exports<'box-react-ui/lib/deprecated/table/TableRow'>; +} +declare module 'box-react-ui/lib/features/access-stats/AccessStats.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/access-stats/AccessStats'>; +} +declare module 'box-react-ui/lib/features/access-stats/AccessStatsItem.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/access-stats/AccessStatsItem'>; +} +declare module 'box-react-ui/lib/features/access-stats/AccessStatsItemsList.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/access-stats/AccessStatsItemsList'>; +} +declare module 'box-react-ui/lib/features/access-stats/messages.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/access-stats/messages'>; +} +declare module 'box-react-ui/lib/features/activity-feed/activity-feed/ActivityFeed.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/activity-feed/activity-feed/ActivityFeed'>; +} +declare module 'box-react-ui/lib/features/activity-feed/activity-feed' { + declare module.exports: $Exports<'box-react-ui/lib/features/activity-feed/activity-feed/index'>; +} +declare module 'box-react-ui/lib/features/activity-feed/approval-comment-form/ApprovalCommentForm.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/activity-feed/approval-comment-form/ApprovalCommentForm'>; +} +declare module 'box-react-ui/lib/features/activity-feed/approval-comment-form' { + declare module.exports: $Exports<'box-react-ui/lib/features/activity-feed/approval-comment-form/index'>; +} +declare module 'box-react-ui/lib/features/activity-feed/comment/Comment.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/activity-feed/comment/Comment'>; +} +declare module 'box-react-ui/lib/features/activity-feed/comment/CommentText.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/activity-feed/comment/CommentText'>; +} +declare module 'box-react-ui/lib/features/activity-feed/comment' { + declare module.exports: $Exports<'box-react-ui/lib/features/activity-feed/comment/index'>; +} +declare module 'box-react-ui/lib/features/activity-feed/comment/InlineDelete.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/activity-feed/comment/InlineDelete'>; +} +declare module 'box-react-ui/lib/features/activity-feed/comment/InlineEdit.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/activity-feed/comment/InlineEdit'>; +} +declare module 'box-react-ui/lib/features/activity-feed/comment/Mention.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/activity-feed/comment/Mention'>; +} +declare module 'box-react-ui/lib/features/activity-feed' { + declare module.exports: $Exports<'box-react-ui/lib/features/activity-feed/index'>; +} +declare module 'box-react-ui/lib/features/activity-feed/keywords' { + declare module.exports: $Exports<'box-react-ui/lib/features/activity-feed/keywords/index'>; +} +declare module 'box-react-ui/lib/features/activity-feed/keywords/Keywords.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/activity-feed/keywords/Keywords'>; +} +declare module 'box-react-ui/lib/features/activity-feed/messages.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/activity-feed/messages'>; +} +declare module 'box-react-ui/lib/features/activity-feed/task' { + declare module.exports: $Exports<'box-react-ui/lib/features/activity-feed/task/index'>; +} +declare module 'box-react-ui/lib/features/activity-feed/task/Task.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/activity-feed/task/Task'>; +} +declare module 'box-react-ui/lib/features/activity-feed/utils/formatTaggedMessage.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/activity-feed/utils/formatTaggedMessage'>; +} +declare module 'box-react-ui/lib/features/activity-feed/version/CollapsedVersion.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/activity-feed/version/CollapsedVersion'>; +} +declare module 'box-react-ui/lib/features/activity-feed/version' { + declare module.exports: $Exports<'box-react-ui/lib/features/activity-feed/version/index'>; +} +declare module 'box-react-ui/lib/features/activity-feed/version/Version.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/activity-feed/version/Version'>; +} +declare module 'box-react-ui/lib/features/activity-feed/version/VersionError.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/activity-feed/version/VersionError'>; +} +declare module 'box-react-ui/lib/features/classification/ClassificationBadge.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/classification/ClassificationBadge'>; +} +declare module 'box-react-ui/lib/features/classification/ClassificationProperty.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/classification/ClassificationProperty'>; +} +declare module 'box-react-ui/lib/features/classification/messages.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/classification/messages'>; +} +declare module 'box-react-ui/lib/features/content-explorer/content-explorer-modal-container/ContentExplorerModalContainer.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/content-explorer/content-explorer-modal-container/ContentExplorerModalContainer'>; +} +declare module 'box-react-ui/lib/features/content-explorer/content-explorer-modal-container' { + declare module.exports: $Exports<'box-react-ui/lib/features/content-explorer/content-explorer-modal-container/index'>; +} +declare module 'box-react-ui/lib/features/content-explorer/content-explorer-modal/ContentExplorerModal.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/content-explorer/content-explorer-modal/ContentExplorerModal'>; +} +declare module 'box-react-ui/lib/features/content-explorer/content-explorer-modal' { + declare module.exports: $Exports<'box-react-ui/lib/features/content-explorer/content-explorer-modal/index'>; +} +declare module 'box-react-ui/lib/features/content-explorer/content-explorer/ContentExplorer.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/content-explorer/content-explorer/ContentExplorer'>; +} +declare module 'box-react-ui/lib/features/content-explorer/content-explorer/ContentExplorerActionButtons.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/content-explorer/content-explorer/ContentExplorerActionButtons'>; +} +declare module 'box-react-ui/lib/features/content-explorer/content-explorer/ContentExplorerBreadcrumbs.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/content-explorer/content-explorer/ContentExplorerBreadcrumbs'>; +} +declare module 'box-react-ui/lib/features/content-explorer/content-explorer/ContentExplorerEmptyState.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/content-explorer/content-explorer/ContentExplorerEmptyState'>; +} +declare module 'box-react-ui/lib/features/content-explorer/content-explorer/ContentExplorerHeaderActions.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/content-explorer/content-explorer/ContentExplorerHeaderActions'>; +} +declare module 'box-react-ui/lib/features/content-explorer/content-explorer/ContentExplorerNewFolderButton.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/content-explorer/content-explorer/ContentExplorerNewFolderButton'>; +} +declare module 'box-react-ui/lib/features/content-explorer/content-explorer/ContentExplorerSearch.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/content-explorer/content-explorer/ContentExplorerSearch'>; +} +declare module 'box-react-ui/lib/features/content-explorer/content-explorer' { + declare module.exports: $Exports<'box-react-ui/lib/features/content-explorer/content-explorer/index'>; +} +declare module 'box-react-ui/lib/features/content-explorer' { + declare module.exports: $Exports<'box-react-ui/lib/features/content-explorer/index'>; +} +declare module 'box-react-ui/lib/features/content-explorer/item-list' { + declare module.exports: $Exports<'box-react-ui/lib/features/content-explorer/item-list/index'>; +} +declare module 'box-react-ui/lib/features/content-explorer/item-list/ItemList.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/content-explorer/item-list/ItemList'>; +} +declare module 'box-react-ui/lib/features/content-explorer/item-list/ItemListButton.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/content-explorer/item-list/ItemListButton'>; +} +declare module 'box-react-ui/lib/features/content-explorer/item-list/ItemListIcon.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/content-explorer/item-list/ItemListIcon'>; +} +declare module 'box-react-ui/lib/features/content-explorer/item-list/ItemListLoadingPlaceholder.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/content-explorer/item-list/ItemListLoadingPlaceholder'>; +} +declare module 'box-react-ui/lib/features/content-explorer/item-list/ItemListName.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/content-explorer/item-list/ItemListName'>; +} +declare module 'box-react-ui/lib/features/content-explorer/item-types.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/content-explorer/item-types'>; +} +declare module 'box-react-ui/lib/features/content-explorer/messages.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/content-explorer/messages'>; +} +declare module 'box-react-ui/lib/features/content-explorer/modes.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/content-explorer/modes'>; +} +declare module 'box-react-ui/lib/features/content-explorer/new-folder-modal' { + declare module.exports: $Exports<'box-react-ui/lib/features/content-explorer/new-folder-modal/index'>; +} +declare module 'box-react-ui/lib/features/content-explorer/new-folder-modal/NewFolderModal.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/content-explorer/new-folder-modal/NewFolderModal'>; +} +declare module 'box-react-ui/lib/features/content-explorer/prop-types.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/content-explorer/prop-types'>; +} +declare module 'box-react-ui/lib/features/in-app-message/create-message-form/constants.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/in-app-message/create-message-form/constants'>; +} +declare module 'box-react-ui/lib/features/in-app-message/create-message-form/CreateMessageForm.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/in-app-message/create-message-form/CreateMessageForm'>; +} +declare module 'box-react-ui/lib/features/in-app-message/create-message-form' { + declare module.exports: $Exports<'box-react-ui/lib/features/in-app-message/create-message-form/index'>; +} +declare module 'box-react-ui/lib/features/in-app-message' { + declare module.exports: $Exports<'box-react-ui/lib/features/in-app-message/index'>; +} +declare module 'box-react-ui/lib/features/in-app-message/targeting-expression-editor/constants.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/in-app-message/targeting-expression-editor/constants'>; +} +declare module 'box-react-ui/lib/features/in-app-message/targeting-expression-editor' { + declare module.exports: $Exports<'box-react-ui/lib/features/in-app-message/targeting-expression-editor/index'>; +} +declare module 'box-react-ui/lib/features/in-app-message/targeting-expression-editor/TargetingExpressionEditor.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/in-app-message/targeting-expression-editor/TargetingExpressionEditor'>; +} +declare module 'box-react-ui/lib/features/in-app-message/targeting-expression-editor/TargetingExpressionRow.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/in-app-message/targeting-expression-editor/TargetingExpressionRow'>; +} +declare module 'box-react-ui/lib/features/in-app-message/targeting-rule/constants.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/in-app-message/targeting-rule/constants'>; +} +declare module 'box-react-ui/lib/features/in-app-message/targeting-rule' { + declare module.exports: $Exports<'box-react-ui/lib/features/in-app-message/targeting-rule/index'>; +} +declare module 'box-react-ui/lib/features/in-app-message/targeting-rule/RuleContextInputs.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/in-app-message/targeting-rule/RuleContextInputs'>; +} +declare module 'box-react-ui/lib/features/in-app-message/targeting-rule/RuleSelect.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/in-app-message/targeting-rule/RuleSelect'>; +} +declare module 'box-react-ui/lib/features/in-app-message/targeting-rule/RuleTypeSelect.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/in-app-message/targeting-rule/RuleTypeSelect'>; +} +declare module 'box-react-ui/lib/features/in-app-message/targeting-rule/RuleValueInputAmong.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/in-app-message/targeting-rule/RuleValueInputAmong'>; +} +declare module 'box-react-ui/lib/features/in-app-message/targeting-rule/RuleValueInputEqual.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/in-app-message/targeting-rule/RuleValueInputEqual'>; +} +declare module 'box-react-ui/lib/features/in-app-message/targeting-rule/RuleValueInputsInRange.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/in-app-message/targeting-rule/RuleValueInputsInRange'>; +} +declare module 'box-react-ui/lib/features/in-app-message/targeting-rule/TargetingRule.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/in-app-message/targeting-rule/TargetingRule'>; +} +declare module 'box-react-ui/lib/features/invite-collaborators-modal' { + declare module.exports: $Exports<'box-react-ui/lib/features/invite-collaborators-modal/index'>; +} +declare module 'box-react-ui/lib/features/invite-collaborators-modal/InviteCollaboratorsModal.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/invite-collaborators-modal/InviteCollaboratorsModal'>; +} +declare module 'box-react-ui/lib/features/invite-collaborators-modal/messages.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/invite-collaborators-modal/messages'>; +} +declare module 'box-react-ui/lib/features/invite-collaborators-modal/PermissionFlyout.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/invite-collaborators-modal/PermissionFlyout'>; +} +declare module 'box-react-ui/lib/features/item-details/EditableDescription.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/item-details/EditableDescription'>; +} +declare module 'box-react-ui/lib/features/item-details/EditableURL.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/item-details/EditableURL'>; +} +declare module 'box-react-ui/lib/features/item-details/ItemExpirationNotice.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/item-details/ItemExpirationNotice'>; +} +declare module 'box-react-ui/lib/features/item-details/ItemProperties.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/item-details/ItemProperties'>; +} +declare module 'box-react-ui/lib/features/item-details/messages.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/item-details/messages'>; +} +declare module 'box-react-ui/lib/features/item-details/ReadonlyDescription.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/item-details/ReadonlyDescription'>; +} +declare module 'box-react-ui/lib/features/item-details/RetentionPolicy.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/item-details/RetentionPolicy'>; +} +declare module 'box-react-ui/lib/features/item-details/SharedLinkExpirationNotice.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/item-details/SharedLinkExpirationNotice'>; +} +declare module 'box-react-ui/lib/features/item-details/VersionHistoryLink.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/item-details/VersionHistoryLink'>; +} +declare module 'box-react-ui/lib/features/left-sidebar/Callout.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/left-sidebar/Callout'>; +} +declare module 'box-react-ui/lib/features/left-sidebar/CopyrightFooter.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/left-sidebar/CopyrightFooter'>; +} +declare module 'box-react-ui/lib/features/left-sidebar/icons/IconAdminConsole.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/left-sidebar/icons/IconAdminConsole'>; +} +declare module 'box-react-ui/lib/features/left-sidebar/icons/IconAllFiles.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/left-sidebar/icons/IconAllFiles'>; +} +declare module 'box-react-ui/lib/features/left-sidebar/icons/IconDevConsole.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/left-sidebar/icons/IconDevConsole'>; +} +declare module 'box-react-ui/lib/features/left-sidebar/icons/IconFavorites.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/left-sidebar/icons/IconFavorites'>; +} +declare module 'box-react-ui/lib/features/left-sidebar/icons/IconFeed.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/left-sidebar/icons/IconFeed'>; +} +declare module 'box-react-ui/lib/features/left-sidebar/icons/IconNotes.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/left-sidebar/icons/IconNotes'>; +} +declare module 'box-react-ui/lib/features/left-sidebar/icons/IconNotifications.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/left-sidebar/icons/IconNotifications'>; +} +declare module 'box-react-ui/lib/features/left-sidebar/icons/IconOwnedByMe.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/left-sidebar/icons/IconOwnedByMe'>; +} +declare module 'box-react-ui/lib/features/left-sidebar/icons/IconRecents.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/left-sidebar/icons/IconRecents'>; +} +declare module 'box-react-ui/lib/features/left-sidebar/icons/IconRelay.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/left-sidebar/icons/IconRelay'>; +} +declare module 'box-react-ui/lib/features/left-sidebar/icons/IconReturnToAdminConsole.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/left-sidebar/icons/IconReturnToAdminConsole'>; +} +declare module 'box-react-ui/lib/features/left-sidebar/icons/IconSharedWithMe.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/left-sidebar/icons/IconSharedWithMe'>; +} +declare module 'box-react-ui/lib/features/left-sidebar/icons/IconSynced.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/left-sidebar/icons/IconSynced'>; +} +declare module 'box-react-ui/lib/features/left-sidebar/icons/IconTrash.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/left-sidebar/icons/IconTrash'>; +} +declare module 'box-react-ui/lib/features/left-sidebar' { + declare module.exports: $Exports<'box-react-ui/lib/features/left-sidebar/index'>; +} +declare module 'box-react-ui/lib/features/left-sidebar/InstantLogin.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/left-sidebar/InstantLogin'>; +} +declare module 'box-react-ui/lib/features/left-sidebar/LeftSidebar.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/left-sidebar/LeftSidebar'>; +} +declare module 'box-react-ui/lib/features/left-sidebar/LeftSidebarDropWrapper.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/left-sidebar/LeftSidebarDropWrapper'>; +} +declare module 'box-react-ui/lib/features/left-sidebar/LeftSidebarIconWrapper.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/left-sidebar/LeftSidebarIconWrapper'>; +} +declare module 'box-react-ui/lib/features/left-sidebar/LeftSidebarLink.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/left-sidebar/LeftSidebarLink'>; +} +declare module 'box-react-ui/lib/features/left-sidebar/LeftSidebarLinkCallout.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/left-sidebar/LeftSidebarLinkCallout'>; +} +declare module 'box-react-ui/lib/features/left-sidebar/NewItemsIndicator.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/left-sidebar/NewItemsIndicator'>; +} +declare module 'box-react-ui/lib/features/left-sidebar/RemoveButton.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/left-sidebar/RemoveButton'>; +} +declare module 'box-react-ui/lib/features/metadata-instance-editor/CascadePolicy.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/metadata-instance-editor/CascadePolicy'>; +} +declare module 'box-react-ui/lib/features/metadata-instance-editor/constants.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/metadata-instance-editor/constants'>; +} +declare module 'box-react-ui/lib/features/metadata-instance-editor/CustomInstance.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/metadata-instance-editor/CustomInstance'>; +} +declare module 'box-react-ui/lib/features/metadata-instance-editor/CustomInstanceNewField.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/metadata-instance-editor/CustomInstanceNewField'>; +} +declare module 'box-react-ui/lib/features/metadata-instance-editor/EmptyContent.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/metadata-instance-editor/EmptyContent'>; +} +declare module 'box-react-ui/lib/features/metadata-instance-editor/fields/CustomField.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/metadata-instance-editor/fields/CustomField'>; +} +declare module 'box-react-ui/lib/features/metadata-instance-editor/fields/DateField.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/metadata-instance-editor/fields/DateField'>; +} +declare module 'box-react-ui/lib/features/metadata-instance-editor/fields/EnumField.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/metadata-instance-editor/fields/EnumField'>; +} +declare module 'box-react-ui/lib/features/metadata-instance-editor/fields/Field.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/metadata-instance-editor/fields/Field'>; +} +declare module 'box-react-ui/lib/features/metadata-instance-editor/fields/FloatField.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/metadata-instance-editor/fields/FloatField'>; +} +declare module 'box-react-ui/lib/features/metadata-instance-editor/fields/IntegerField.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/metadata-instance-editor/fields/IntegerField'>; +} +declare module 'box-react-ui/lib/features/metadata-instance-editor/fields/MultiSelectField.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/metadata-instance-editor/fields/MultiSelectField'>; +} +declare module 'box-react-ui/lib/features/metadata-instance-editor/fields/ReadOnlyField.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/metadata-instance-editor/fields/ReadOnlyField'>; +} +declare module 'box-react-ui/lib/features/metadata-instance-editor/fields/TextField.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/metadata-instance-editor/fields/TextField'>; +} +declare module 'box-react-ui/lib/features/metadata-instance-editor/fields/validateField.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/metadata-instance-editor/fields/validateField'>; +} +declare module 'box-react-ui/lib/features/metadata-instance-editor/flowTypes.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/metadata-instance-editor/flowTypes'>; +} +declare module 'box-react-ui/lib/features/metadata-instance-editor/Footer.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/metadata-instance-editor/Footer'>; +} +declare module 'box-react-ui/lib/features/metadata-instance-editor/Header.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/metadata-instance-editor/Header'>; +} +declare module 'box-react-ui/lib/features/metadata-instance-editor/Instance.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/metadata-instance-editor/Instance'>; +} +declare module 'box-react-ui/lib/features/metadata-instance-editor/messages.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/metadata-instance-editor/messages'>; +} +declare module 'box-react-ui/lib/features/metadata-instance-editor/MetadataInstanceConfirmDialog.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/metadata-instance-editor/MetadataInstanceConfirmDialog'>; +} +declare module 'box-react-ui/lib/features/metadata-instance-editor/MetadataInstanceEditor.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/metadata-instance-editor/MetadataInstanceEditor'>; +} +declare module 'box-react-ui/lib/features/metadata-instance-editor/TemplatedInstance.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/metadata-instance-editor/TemplatedInstance'>; +} +declare module 'box-react-ui/lib/features/metadata-instance-editor/TemplateDropdown.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/metadata-instance-editor/TemplateDropdown'>; +} +declare module 'box-react-ui/lib/features/presence/constants.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/presence/constants'>; +} +declare module 'box-react-ui/lib/features/presence' { + declare module.exports: $Exports<'box-react-ui/lib/features/presence/index'>; +} +declare module 'box-react-ui/lib/features/presence/messages.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/presence/messages'>; +} +declare module 'box-react-ui/lib/features/presence/Presence.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/presence/Presence'>; +} +declare module 'box-react-ui/lib/features/presence/PresenceAvatar.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/presence/PresenceAvatar'>; +} +declare module 'box-react-ui/lib/features/presence/PresenceDropdown.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/presence/PresenceDropdown'>; +} +declare module 'box-react-ui/lib/features/presence/PresenceLink.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/presence/PresenceLink'>; +} +declare module 'box-react-ui/lib/features/presence/propTypes.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/presence/propTypes'>; +} +declare module 'box-react-ui/lib/features/presence/utils/presenceUtils.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/presence/utils/presenceUtils'>; +} +declare module 'box-react-ui/lib/features/quick-search' { + declare module.exports: $Exports<'box-react-ui/lib/features/quick-search/index'>; +} +declare module 'box-react-ui/lib/features/quick-search/messages.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/quick-search/messages'>; +} +declare module 'box-react-ui/lib/features/quick-search/QuickSearch.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/quick-search/QuickSearch'>; +} +declare module 'box-react-ui/lib/features/quick-search/QuickSearchItem.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/quick-search/QuickSearchItem'>; +} +declare module 'box-react-ui/lib/features/quick-search/QuickSearchMessage.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/quick-search/QuickSearchMessage'>; +} +declare module 'box-react-ui/lib/features/quick-search/QuickSearchSelector.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/quick-search/QuickSearchSelector'>; +} +declare module 'box-react-ui/lib/features/security-cloud-game/DragCloud.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/security-cloud-game/DragCloud'>; +} +declare module 'box-react-ui/lib/features/security-cloud-game/DropCloud.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/security-cloud-game/DropCloud'>; +} +declare module 'box-react-ui/lib/features/security-cloud-game' { + declare module.exports: $Exports<'box-react-ui/lib/features/security-cloud-game/index'>; +} +declare module 'box-react-ui/lib/features/security-cloud-game/messages.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/security-cloud-game/messages'>; +} +declare module 'box-react-ui/lib/features/security-cloud-game/SecurityCloudGame.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/security-cloud-game/SecurityCloudGame'>; +} +declare module 'box-react-ui/lib/features/share' { + declare module.exports: $Exports<'box-react-ui/lib/features/share/index'>; +} +declare module 'box-react-ui/lib/features/share/messages.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/share/messages'>; +} +declare module 'box-react-ui/lib/features/share/ShareMenu.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/share/ShareMenu'>; +} +declare module 'box-react-ui/lib/features/shared-link-modal/AccessDescription.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/shared-link-modal/AccessDescription'>; +} +declare module 'box-react-ui/lib/features/shared-link-modal/AccessLabel.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/shared-link-modal/AccessLabel'>; +} +declare module 'box-react-ui/lib/features/shared-link-modal/AccessMenu.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/shared-link-modal/AccessMenu'>; +} +declare module 'box-react-ui/lib/features/shared-link-modal/constants.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/shared-link-modal/constants'>; +} +declare module 'box-react-ui/lib/features/shared-link-modal/EmailSharedLink.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/shared-link-modal/EmailSharedLink'>; +} +declare module 'box-react-ui/lib/features/shared-link-modal' { + declare module.exports: $Exports<'box-react-ui/lib/features/shared-link-modal/index'>; +} +declare module 'box-react-ui/lib/features/shared-link-modal/messages.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/shared-link-modal/messages'>; +} +declare module 'box-react-ui/lib/features/shared-link-modal/PermissionMenu.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/shared-link-modal/PermissionMenu'>; +} +declare module 'box-react-ui/lib/features/shared-link-modal/propTypes.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/shared-link-modal/propTypes'>; +} +declare module 'box-react-ui/lib/features/shared-link-modal/RemoveLinkConfirmModal.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/shared-link-modal/RemoveLinkConfirmModal'>; +} +declare module 'box-react-ui/lib/features/shared-link-modal/SharedLink.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/shared-link-modal/SharedLink'>; +} +declare module 'box-react-ui/lib/features/shared-link-modal/SharedLinkAccess.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/shared-link-modal/SharedLinkAccess'>; +} +declare module 'box-react-ui/lib/features/shared-link-modal/SharedLinkModal.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/shared-link-modal/SharedLinkModal'>; +} +declare module 'box-react-ui/lib/features/shared-link-settings-modal/AllowDownloadSection.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/shared-link-settings-modal/AllowDownloadSection'>; +} +declare module 'box-react-ui/lib/features/shared-link-settings-modal/ExpirationSection.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/shared-link-settings-modal/ExpirationSection'>; +} +declare module 'box-react-ui/lib/features/shared-link-settings-modal' { + declare module.exports: $Exports<'box-react-ui/lib/features/shared-link-settings-modal/index'>; +} +declare module 'box-react-ui/lib/features/shared-link-settings-modal/messages.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/shared-link-settings-modal/messages'>; +} +declare module 'box-react-ui/lib/features/shared-link-settings-modal/PasswordSection.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/shared-link-settings-modal/PasswordSection'>; +} +declare module 'box-react-ui/lib/features/shared-link-settings-modal/SharedLinkSettingsModal.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/shared-link-settings-modal/SharedLinkSettingsModal'>; +} +declare module 'box-react-ui/lib/features/shared-link-settings-modal/VanityNameSection.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/shared-link-settings-modal/VanityNameSection'>; +} +declare module 'box-react-ui/lib/features/unified-share-modal/AccessDescription.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/unified-share-modal/AccessDescription'>; +} +declare module 'box-react-ui/lib/features/unified-share-modal/AccessLabel.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/unified-share-modal/AccessLabel'>; +} +declare module 'box-react-ui/lib/features/unified-share-modal/AccessMenu.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/unified-share-modal/AccessMenu'>; +} +declare module 'box-react-ui/lib/features/unified-share-modal/constants.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/unified-share-modal/constants'>; +} +declare module 'box-react-ui/lib/features/unified-share-modal/flowTypes.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/unified-share-modal/flowTypes'>; +} +declare module 'box-react-ui/lib/features/unified-share-modal' { + declare module.exports: $Exports<'box-react-ui/lib/features/unified-share-modal/index'>; +} +declare module 'box-react-ui/lib/features/unified-share-modal/InviteePermissionsMenu.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/unified-share-modal/InviteePermissionsMenu'>; +} +declare module 'box-react-ui/lib/features/unified-share-modal/messages.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/unified-share-modal/messages'>; +} +declare module 'box-react-ui/lib/features/unified-share-modal/PermissionMenu.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/unified-share-modal/PermissionMenu'>; +} +declare module 'box-react-ui/lib/features/unified-share-modal/RemoveLinkConfirmModal.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/unified-share-modal/RemoveLinkConfirmModal'>; +} +declare module 'box-react-ui/lib/features/unified-share-modal/SharedLink.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/unified-share-modal/SharedLink'>; +} +declare module 'box-react-ui/lib/features/unified-share-modal/SharedLinkAccess.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/unified-share-modal/SharedLinkAccess'>; +} +declare module 'box-react-ui/lib/features/unified-share-modal/UnifiedShareModal.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/unified-share-modal/UnifiedShareModal'>; +} +declare module 'box-react-ui/lib/features/version-history-modal/constants.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/version-history-modal/constants'>; +} +declare module 'box-react-ui/lib/features/version-history-modal/FileVersionActions.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/version-history-modal/FileVersionActions'>; +} +declare module 'box-react-ui/lib/features/version-history-modal/FileVersionInfo.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/version-history-modal/FileVersionInfo'>; +} +declare module 'box-react-ui/lib/features/version-history-modal/FileVersionList.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/version-history-modal/FileVersionList'>; +} +declare module 'box-react-ui/lib/features/version-history-modal/FileVersionListItem.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/version-history-modal/FileVersionListItem'>; +} +declare module 'box-react-ui/lib/features/version-history-modal' { + declare module.exports: $Exports<'box-react-ui/lib/features/version-history-modal/index'>; +} +declare module 'box-react-ui/lib/features/version-history-modal/messages.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/version-history-modal/messages'>; +} +declare module 'box-react-ui/lib/features/version-history-modal/prop-types.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/version-history-modal/prop-types'>; +} +declare module 'box-react-ui/lib/features/version-history-modal/VersionHistoryModal.js' { + declare module.exports: $Exports<'box-react-ui/lib/features/version-history-modal/VersionHistoryModal'>; +} +declare module 'box-react-ui/lib/icons/accessible-svg/AccessibleSVG.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/accessible-svg/AccessibleSVG'>; +} +declare module 'box-react-ui/lib/icons/accessible-svg' { + declare module.exports: $Exports<'box-react-ui/lib/icons/accessible-svg/index'>; +} + +declare module 'box-react-ui/lib/icons/annotations/IconHighlightAnnotation' { + declare module.exports: $Exports<'box-react-ui/lib/icons/annotations/IconHighlightAnnotation'>; +} + +declare module 'box-react-ui/lib/icons/annotations/IconHighlightCommentAnnotation' { + declare module.exports: $Exports<'box-react-ui/lib/icons/annotations/IconHighlightCommentAnnotation'>; +} + +declare module 'box-react-ui/lib/icons/annotations/IconPointAnnotation' { + declare module.exports: $Exports<'box-react-ui/lib/icons/annotations/IconPointAnnotation'>; +} +declare module 'box-react-ui/lib/icons/adobe-sign/IconAdobeSign.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/adobe-sign/IconAdobeSign'>; +} +declare module 'box-react-ui/lib/icons/avatars/UnknownUserAvatar.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/avatars/UnknownUserAvatar'>; +} +declare module 'box-react-ui/lib/icons/badges/CoauthoringBadge.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/badges/CoauthoringBadge'>; +} +declare module 'box-react-ui/lib/icons/badges/CollaborationBadge.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/badges/CollaborationBadge'>; +} +declare module 'box-react-ui/lib/icons/badges/ExpirationBadge.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/badges/ExpirationBadge'>; +} +declare module 'box-react-ui/lib/icons/badges/InfoBadge.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/badges/InfoBadge'>; +} +declare module 'box-react-ui/lib/icons/badges/LockBadge.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/badges/LockBadge'>; +} +declare module 'box-react-ui/lib/icons/badges/QuarantineBadge.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/badges/QuarantineBadge'>; +} +declare module 'box-react-ui/lib/icons/badges/SharedLinkBadge.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/badges/SharedLinkBadge'>; +} +declare module 'box-react-ui/lib/icons/bookmark-icon/BookmarkIcon.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/bookmark-icon/BookmarkIcon'>; +} +declare module 'box-react-ui/lib/icons/bookmark-icon' { + declare module.exports: $Exports<'box-react-ui/lib/icons/bookmark-icon/index'>; +} +declare module 'box-react-ui/lib/icons/box-notes/IconBoxNotes.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/box-notes/IconBoxNotes'>; +} +declare module 'box-react-ui/lib/icons/box-tools/IconBoxToolsDownload.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/box-tools/IconBoxToolsDownload'>; +} +declare module 'box-react-ui/lib/icons/box-tools/IconBoxToolsInstall.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/box-tools/IconBoxToolsInstall'>; +} +declare module 'box-react-ui/lib/icons/box-tools/IconBoxToolsUpgradeBrowser.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/box-tools/IconBoxToolsUpgradeBrowser'>; +} +declare module 'box-react-ui/lib/icons/file-icon/FileIcon.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/file-icon/FileIcon'>; +} +declare module 'box-react-ui/lib/icons/file-icon' { + declare module.exports: $Exports<'box-react-ui/lib/icons/file-icon/index'>; +} +declare module 'box-react-ui/lib/icons/file/IconFileAudio.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/file/IconFileAudio'>; +} +declare module 'box-react-ui/lib/icons/file/IconFileBoxNote.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/file/IconFileBoxNote'>; +} +declare module 'box-react-ui/lib/icons/file/IconFileCode.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/file/IconFileCode'>; +} +declare module 'box-react-ui/lib/icons/file/IconFileDefault.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/file/IconFileDefault'>; +} +declare module 'box-react-ui/lib/icons/file/IconFileDocument.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/file/IconFileDocument'>; +} +declare module 'box-react-ui/lib/icons/file/IconFileExcelSpreadsheet.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/file/IconFileExcelSpreadsheet'>; +} +declare module 'box-react-ui/lib/icons/file/IconFileGoogleDocs.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/file/IconFileGoogleDocs'>; +} +declare module 'box-react-ui/lib/icons/file/IconFileGoogleSheets.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/file/IconFileGoogleSheets'>; +} +declare module 'box-react-ui/lib/icons/file/IconFileGoogleSlides.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/file/IconFileGoogleSlides'>; +} +declare module 'box-react-ui/lib/icons/file/IconFileIllustrator.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/file/IconFileIllustrator'>; +} +declare module 'box-react-ui/lib/icons/file/IconFileImage.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/file/IconFileImage'>; +} +declare module 'box-react-ui/lib/icons/file/IconFileIndesign.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/file/IconFileIndesign'>; +} +declare module 'box-react-ui/lib/icons/file/IconFileKeynote.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/file/IconFileKeynote'>; +} +declare module 'box-react-ui/lib/icons/file/IconFileNumbers.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/file/IconFileNumbers'>; +} +declare module 'box-react-ui/lib/icons/file/IconFilePages.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/file/IconFilePages'>; +} +declare module 'box-react-ui/lib/icons/file/IconFilePDF.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/file/IconFilePDF'>; +} +declare module 'box-react-ui/lib/icons/file/IconFilePhotoshop.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/file/IconFilePhotoshop'>; +} +declare module 'box-react-ui/lib/icons/file/IconFilePowerpointPresentation.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/file/IconFilePowerpointPresentation'>; +} +declare module 'box-react-ui/lib/icons/file/IconFilePresentation.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/file/IconFilePresentation'>; +} +declare module 'box-react-ui/lib/icons/file/IconFileSpreadsheet.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/file/IconFileSpreadsheet'>; +} +declare module 'box-react-ui/lib/icons/file/IconFileText.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/file/IconFileText'>; +} +declare module 'box-react-ui/lib/icons/file/IconFileThreeD.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/file/IconFileThreeD'>; +} +declare module 'box-react-ui/lib/icons/file/IconFileVector.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/file/IconFileVector'>; +} +declare module 'box-react-ui/lib/icons/file/IconFileVideo.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/file/IconFileVideo'>; +} +declare module 'box-react-ui/lib/icons/file/IconFileWordDocument.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/file/IconFileWordDocument'>; +} +declare module 'box-react-ui/lib/icons/file/IconFileZip.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/file/IconFileZip'>; +} +declare module 'box-react-ui/lib/icons/folder-icon/FolderIcon.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/folder-icon/FolderIcon'>; +} +declare module 'box-react-ui/lib/icons/folder-icon' { + declare module.exports: $Exports<'box-react-ui/lib/icons/folder-icon/index'>; +} +declare module 'box-react-ui/lib/icons/folder/IconFolderCollab.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/folder/IconFolderCollab'>; +} +declare module 'box-react-ui/lib/icons/folder/IconFolderExternal.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/folder/IconFolderExternal'>; +} +declare module 'box-react-ui/lib/icons/folder/IconFolderPersonal.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/folder/IconFolderPersonal'>; +} +declare module 'box-react-ui/lib/icons/folder/IconSmallFolder.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/folder/IconSmallFolder'>; +} +declare module 'box-react-ui/lib/icons/general/IconAdd.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconAdd'>; +} +declare module 'box-react-ui/lib/icons/general/IconAddMetadataEmptyState.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconAddMetadataEmptyState'>; +} +declare module 'box-react-ui/lib/icons/general/IconAddTags.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconAddTags'>; +} +declare module 'box-react-ui/lib/icons/general/IconAddThin.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconAddThin'>; +} +declare module 'box-react-ui/lib/icons/general/IconAdvancedFilters.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconAdvancedFilters'>; +} +declare module 'box-react-ui/lib/icons/general/IconAlert.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconAlert'>; +} +declare module 'box-react-ui/lib/icons/general/IconAlertCircle.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconAlertCircle'>; +} +declare module 'box-react-ui/lib/icons/general/IconAlignLeft.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconAlignLeft'>; +} +declare module 'box-react-ui/lib/icons/general/IconAllFiles.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconAllFiles'>; +} +declare module 'box-react-ui/lib/icons/general/IconApps.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconApps'>; +} +declare module 'box-react-ui/lib/icons/general/IconAutomation.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconAutomation'>; +} +declare module 'box-react-ui/lib/icons/general/IconBarGraph.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconBarGraph'>; +} +declare module 'box-react-ui/lib/icons/general/IconBell.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconBell'>; +} +declare module 'box-react-ui/lib/icons/general/IconBell2.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconBell2'>; +} +declare module 'box-react-ui/lib/icons/general/IconBilling.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconBilling'>; +} +declare module 'box-react-ui/lib/icons/general/IconBox3DCenter.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconBox3DCenter'>; +} +declare module 'box-react-ui/lib/icons/general/IconBreadcrumbArrow.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconBreadcrumbArrow'>; +} +declare module 'box-react-ui/lib/icons/general/IconCalendar.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconCalendar'>; +} +declare module 'box-react-ui/lib/icons/general/IconCaretDown.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconCaretDown'>; +} +declare module 'box-react-ui/lib/icons/general/IconChat.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconChat'>; +} +declare module 'box-react-ui/lib/icons/general/IconChatRound.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconChatRound'>; +} +declare module 'box-react-ui/lib/icons/general/IconCheck.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconCheck'>; +} +declare module 'box-react-ui/lib/icons/general/IconChevron.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconChevron'>; +} +declare module 'box-react-ui/lib/icons/general/IconClear.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconClear'>; +} +declare module 'box-react-ui/lib/icons/general/IconClock.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconClock'>; +} +declare module 'box-react-ui/lib/icons/general/IconClockPast.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconClockPast'>; +} +declare module 'box-react-ui/lib/icons/general/IconClose.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconClose'>; +} +declare module 'box-react-ui/lib/icons/general/IconCloud.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconCloud'>; +} +declare module 'box-react-ui/lib/icons/general/IconCodeBlock.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconCodeBlock'>; +} +declare module 'box-react-ui/lib/icons/general/IconCollaboration.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconCollaboration'>; +} +declare module 'box-react-ui/lib/icons/general/IconCollaborators.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconCollaborators'>; +} +declare module 'box-react-ui/lib/icons/general/IconCollaboratorsRestricted.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconCollaboratorsRestricted'>; +} +declare module 'box-react-ui/lib/icons/general/IconCollapse.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconCollapse'>; +} +declare module 'box-react-ui/lib/icons/general/IconComment.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconComment'>; +} +declare module 'box-react-ui/lib/icons/general/IconCommentsBadge.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconCommentsBadge'>; +} +declare module 'box-react-ui/lib/icons/general/IconComposeNote.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconComposeNote'>; +} +declare module 'box-react-ui/lib/icons/general/IconConePopper.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconConePopper'>; +} +declare module 'box-react-ui/lib/icons/general/IconCopy.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconCopy'>; +} +declare module 'box-react-ui/lib/icons/general/IconCreditCardAmex.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconCreditCardAmex'>; +} +declare module 'box-react-ui/lib/icons/general/IconCreditCardDiscover.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconCreditCardDiscover'>; +} +declare module 'box-react-ui/lib/icons/general/IconCreditCardJCB.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconCreditCardJCB'>; +} +declare module 'box-react-ui/lib/icons/general/IconCreditCardMasterCard.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconCreditCardMasterCard'>; +} +declare module 'box-react-ui/lib/icons/general/IconCreditCardVisa.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconCreditCardVisa'>; +} +declare module 'box-react-ui/lib/icons/general/IconDocIllustration.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconDocIllustration'>; +} +declare module 'box-react-ui/lib/icons/general/IconDocInfo.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconDocInfo'>; +} +declare module 'box-react-ui/lib/icons/general/IconDownload.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconDownload'>; +} +declare module 'box-react-ui/lib/icons/general/IconDownloadFile.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconDownloadFile'>; +} +declare module 'box-react-ui/lib/icons/general/IconDownloadSolid.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconDownloadSolid'>; +} +declare module 'box-react-ui/lib/icons/general/IconEdit.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconEdit'>; +} +declare module 'box-react-ui/lib/icons/general/IconEllipsis.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconEllipsis'>; +} +declare module 'box-react-ui/lib/icons/general/IconExpand.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconExpand'>; +} +declare module 'box-react-ui/lib/icons/general/IconExpiration.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconExpiration'>; +} +declare module 'box-react-ui/lib/icons/general/IconExpirationBadge.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconExpirationBadge'>; +} +declare module 'box-react-ui/lib/icons/general/IconExpirationInverted.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconExpirationInverted'>; +} +declare module 'box-react-ui/lib/icons/general/IconEye.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconEye'>; +} +declare module 'box-react-ui/lib/icons/general/IconEyeInverted.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconEyeInverted'>; +} +declare module 'box-react-ui/lib/icons/general/IconFeed.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconFeed'>; +} +declare module 'box-react-ui/lib/icons/general/IconFlag.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconFlag'>; +} +declare module 'box-react-ui/lib/icons/general/IconForward.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconForward'>; +} +declare module 'box-react-ui/lib/icons/general/IconGiftWithWings.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconGiftWithWings'>; +} +declare module 'box-react-ui/lib/icons/general/IconGlobe.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconGlobe'>; +} +declare module 'box-react-ui/lib/icons/general/IconGraduationHat.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconGraduationHat'>; +} +declare module 'box-react-ui/lib/icons/general/IconGridView.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconGridView'>; +} +declare module 'box-react-ui/lib/icons/general/IconHamburger.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconHamburger'>; +} +declare module 'box-react-ui/lib/icons/general/IconHelp.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconHelp'>; +} +declare module 'box-react-ui/lib/icons/general/IconHome.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconHome'>; +} +declare module 'box-react-ui/lib/icons/general/IconInfo.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconInfo'>; +} +declare module 'box-react-ui/lib/icons/general/IconInfoInverted.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconInfoInverted'>; +} +declare module 'box-react-ui/lib/icons/general/IconInformation.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconInformation'>; +} +declare module 'box-react-ui/lib/icons/general/IconInfoThin.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconInfoThin'>; +} +declare module 'box-react-ui/lib/icons/general/IconInviteCollaborators.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconInviteCollaborators'>; +} +declare module 'box-react-ui/lib/icons/general/IconLeftArrow.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconLeftArrow'>; +} +declare module 'box-react-ui/lib/icons/general/IconLink.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconLink'>; +} +declare module 'box-react-ui/lib/icons/general/IconListView.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconListView'>; +} +declare module 'box-react-ui/lib/icons/general/IconLock.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconLock'>; +} +declare module 'box-react-ui/lib/icons/general/IconLogo.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconLogo'>; +} +declare module 'box-react-ui/lib/icons/general/IconMagicWand.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconMagicWand'>; +} +declare module 'box-react-ui/lib/icons/general/IconMail.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconMail'>; +} +declare module 'box-react-ui/lib/icons/general/IconMaximize.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconMaximize'>; +} +declare module 'box-react-ui/lib/icons/general/IconMetadata.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconMetadata'>; +} +declare module 'box-react-ui/lib/icons/general/IconMetadataColored.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconMetadataColored'>; +} +declare module 'box-react-ui/lib/icons/general/IconMetadataThick.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconMetadataThick'>; +} +declare module 'box-react-ui/lib/icons/general/IconMinus.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconMinus'>; +} +declare module 'box-react-ui/lib/icons/general/IconMinusThin.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconMinusThin'>; +} +declare module 'box-react-ui/lib/icons/general/IconMoveCopy.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconMoveCopy'>; +} +declare module 'box-react-ui/lib/icons/general/IconNavigateLeft.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconNavigateLeft'>; +} +declare module 'box-react-ui/lib/icons/general/IconNavigateRight.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconNavigateRight'>; +} +declare module 'box-react-ui/lib/icons/general/IconOpenWith.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconOpenWith'>; +} +declare module 'box-react-ui/lib/icons/general/IconPageBack.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconPageBack'>; +} +declare module 'box-react-ui/lib/icons/general/IconPageForward.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconPageForward'>; +} +declare module 'box-react-ui/lib/icons/general/IconPencil.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconPencil'>; +} +declare module 'box-react-ui/lib/icons/general/IconPencilSolid.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconPencilSolid'>; +} +declare module 'box-react-ui/lib/icons/general/IconPhone.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconPhone'>; +} +declare module 'box-react-ui/lib/icons/general/IconPlus.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconPlus'>; +} +declare module 'box-react-ui/lib/icons/general/IconPlusThin.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconPlusThin'>; +} +declare module 'box-react-ui/lib/icons/general/IconPrint.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconPrint'>; +} +declare module 'box-react-ui/lib/icons/general/IconPrintInverted.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconPrintInverted'>; +} +declare module 'box-react-ui/lib/icons/general/IconRecentFiles.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconRecentFiles'>; +} +declare module 'box-react-ui/lib/icons/general/IconRemove.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconRemove'>; +} +declare module 'box-react-ui/lib/icons/general/IconRename.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconRename'>; +} +declare module 'box-react-ui/lib/icons/general/IconReports.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconReports'>; +} +declare module 'box-react-ui/lib/icons/general/IconRetention.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconRetention'>; +} +declare module 'box-react-ui/lib/icons/general/IconRetry.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconRetry'>; +} +declare module 'box-react-ui/lib/icons/general/IconSadCloud.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconSadCloud'>; +} +declare module 'box-react-ui/lib/icons/general/IconSearch.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconSearch'>; +} +declare module 'box-react-ui/lib/icons/general/IconSetting.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconSetting'>; +} +declare module 'box-react-ui/lib/icons/general/IconSettingInverted.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconSettingInverted'>; +} +declare module 'box-react-ui/lib/icons/general/IconShare.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconShare'>; +} +declare module 'box-react-ui/lib/icons/general/IconSharedLink.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconSharedLink'>; +} +declare module 'box-react-ui/lib/icons/general/IconSharedLinkRestricted.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconSharedLinkRestricted'>; +} +declare module 'box-react-ui/lib/icons/general/IconShield.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconShield'>; +} +declare module 'box-react-ui/lib/icons/general/IconShield2.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconShield2'>; +} +declare module 'box-react-ui/lib/icons/general/IconSidebar.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconSidebar'>; +} +declare module 'box-react-ui/lib/icons/general/IconSidebarLeft.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconSidebarLeft'>; +} +declare module 'box-react-ui/lib/icons/general/IconSmallClose.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconSmallClose'>; +} +declare module 'box-react-ui/lib/icons/general/IconSort.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconSort'>; +} +declare module 'box-react-ui/lib/icons/general/IconSortChevron.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconSortChevron'>; +} +declare module 'box-react-ui/lib/icons/general/IconStar.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconStar'>; +} +declare module 'box-react-ui/lib/icons/general/IconSync.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconSync'>; +} +declare module 'box-react-ui/lib/icons/general/IconTag.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconTag'>; +} +declare module 'box-react-ui/lib/icons/general/IconThumbsUp.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconThumbsUp'>; +} +declare module 'box-react-ui/lib/icons/general/IconToolbox.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconToolbox'>; +} +declare module 'box-react-ui/lib/icons/general/IconTrackNext.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconTrackNext'>; +} +declare module 'box-react-ui/lib/icons/general/IconTrackPrevious.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconTrackPrevious'>; +} +declare module 'box-react-ui/lib/icons/general/IconTrash.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconTrash'>; +} +declare module 'box-react-ui/lib/icons/general/IconTrophyCup.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconTrophyCup'>; +} +declare module 'box-react-ui/lib/icons/general/IconTrophyCupWithTooltip.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconTrophyCupWithTooltip'>; +} +declare module 'box-react-ui/lib/icons/general/IconUnlock.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconUnlock'>; +} +declare module 'box-react-ui/lib/icons/general/IconUnsync.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconUnsync'>; +} +declare module 'box-react-ui/lib/icons/general/IconUpdated.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconUpdated'>; +} +declare module 'box-react-ui/lib/icons/general/IconUpgradeCloud.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconUpgradeCloud'>; +} +declare module 'box-react-ui/lib/icons/general/IconUpload.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconUpload'>; +} +declare module 'box-react-ui/lib/icons/general/IconUploadCloud.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconUploadCloud'>; +} +declare module 'box-react-ui/lib/icons/general/IconUploadSolid.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconUploadSolid'>; +} +declare module 'box-react-ui/lib/icons/general/IconVerified.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconVerified'>; +} +declare module 'box-react-ui/lib/icons/general/IconWatermark.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/general/IconWatermark'>; +} +declare module 'box-react-ui/lib/icons/google-docs/GoogleDocsIcon.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/google-docs/GoogleDocsIcon'>; +} +declare module 'box-react-ui/lib/icons/google-docs/IconGoogleDocs.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/google-docs/IconGoogleDocs'>; +} +declare module 'box-react-ui/lib/icons/google-docs/IconGoogleSheets.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/google-docs/IconGoogleSheets'>; +} +declare module 'box-react-ui/lib/icons/google-docs/IconGoogleSlides.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/google-docs/IconGoogleSlides'>; +} +declare module 'box-react-ui/lib/icons/item-icon' { + declare module.exports: $Exports<'box-react-ui/lib/icons/item-icon/index'>; +} +declare module 'box-react-ui/lib/icons/item-icon/ItemIcon.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/item-icon/ItemIcon'>; +} +declare module 'box-react-ui/lib/icons/iwork/IconIWorkKeynote.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/iwork/IconIWorkKeynote'>; +} +declare module 'box-react-ui/lib/icons/iwork/IconIWorkKeynoteDesktop.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/iwork/IconIWorkKeynoteDesktop'>; +} +declare module 'box-react-ui/lib/icons/iwork/IconIWorkNumbers.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/iwork/IconIWorkNumbers'>; +} +declare module 'box-react-ui/lib/icons/iwork/IconIWorkNumbersDesktop.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/iwork/IconIWorkNumbersDesktop'>; +} +declare module 'box-react-ui/lib/icons/iwork/IconIWorkPages.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/iwork/IconIWorkPages'>; +} +declare module 'box-react-ui/lib/icons/iwork/IconIWorkPagesDesktop.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/iwork/IconIWorkPagesDesktop'>; +} +declare module 'box-react-ui/lib/icons/iwork/IconIWorkTrio.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/iwork/IconIWorkTrio'>; +} +declare module 'box-react-ui/lib/icons/iwork/IWorkDesktopIcon.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/iwork/IWorkDesktopIcon'>; +} +declare module 'box-react-ui/lib/icons/iwork/IWorkIcon.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/iwork/IWorkIcon'>; +} +declare module 'box-react-ui/lib/icons/microsoft-office/IconExcelDesktop.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/microsoft-office/IconExcelDesktop'>; +} +declare module 'box-react-ui/lib/icons/microsoft-office/IconExcelOnline.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/microsoft-office/IconExcelOnline'>; +} +declare module 'box-react-ui/lib/icons/microsoft-office/IconOfficeWordmark.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/microsoft-office/IconOfficeWordmark'>; +} +declare module 'box-react-ui/lib/icons/microsoft-office/IconPowerPointDesktop.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/microsoft-office/IconPowerPointDesktop'>; +} +declare module 'box-react-ui/lib/icons/microsoft-office/IconPowerPointOnline.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/microsoft-office/IconPowerPointOnline'>; +} +declare module 'box-react-ui/lib/icons/microsoft-office/IconWordDesktop.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/microsoft-office/IconWordDesktop'>; +} +declare module 'box-react-ui/lib/icons/microsoft-office/IconWordOnline.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/microsoft-office/IconWordOnline'>; +} +declare module 'box-react-ui/lib/icons/microsoft-office/OfficeDesktopIcon.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/microsoft-office/OfficeDesktopIcon'>; +} +declare module 'box-react-ui/lib/icons/microsoft-office/OfficeOnlineIcon.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/microsoft-office/OfficeOnlineIcon'>; +} +declare module 'box-react-ui/lib/icons/promotions/IconMobileApp.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/promotions/IconMobileApp'>; +} +declare module 'box-react-ui/lib/icons/promotions/IconNotesLogo.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/promotions/IconNotesLogo'>; +} +declare module 'box-react-ui/lib/icons/promotions/IconSync.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/promotions/IconSync'>; +} +declare module 'box-react-ui/lib/icons/states/AccessStatsEmptyState.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/states/AccessStatsEmptyState'>; +} +declare module 'box-react-ui/lib/icons/states/ActivityFeedEmptyState.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/states/ActivityFeedEmptyState'>; +} +declare module 'box-react-ui/lib/icons/states/CollaboratorsEmptyState.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/states/CollaboratorsEmptyState'>; +} +declare module 'box-react-ui/lib/icons/states/CollectionSidebarEmptyState.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/states/CollectionSidebarEmptyState'>; +} +declare module 'box-react-ui/lib/icons/states/CongratsPartyPeopleState.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/states/CongratsPartyPeopleState'>; +} +declare module 'box-react-ui/lib/icons/states/EnvelopeTrophyState.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/states/EnvelopeTrophyState'>; +} +declare module 'box-react-ui/lib/icons/states/ErrorEmptyState.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/states/ErrorEmptyState'>; +} +declare module 'box-react-ui/lib/icons/states/FavoritesEmptyState.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/states/FavoritesEmptyState'>; +} +declare module 'box-react-ui/lib/icons/states/FeedEmptyState.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/states/FeedEmptyState'>; +} +declare module 'box-react-ui/lib/icons/states/FolderEmptyState.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/states/FolderEmptyState'>; +} +declare module 'box-react-ui/lib/icons/states/MultiSelectState.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/states/MultiSelectState'>; +} +declare module 'box-react-ui/lib/icons/states/RecentsEmptyState.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/states/RecentsEmptyState'>; +} +declare module 'box-react-ui/lib/icons/states/SearchEmptyState.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/states/SearchEmptyState'>; +} +declare module 'box-react-ui/lib/icons/states/SelectedItemsEmptyState.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/states/SelectedItemsEmptyState'>; +} +declare module 'box-react-ui/lib/icons/states/SetDefaultAppState.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/states/SetDefaultAppState'>; +} +declare module 'box-react-ui/lib/icons/states/SharedLinkErrorState.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/states/SharedLinkErrorState'>; +} +declare module 'box-react-ui/lib/icons/states/SyncEmptyState.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/states/SyncEmptyState'>; +} +declare module 'box-react-ui/lib/icons/states/TrashEmptyState.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/states/TrashEmptyState'>; +} +declare module 'box-react-ui/lib/icons/states/UpdatesEmptyState.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/states/UpdatesEmptyState'>; +} +declare module 'box-react-ui/lib/icons/states/UploadEmptyState.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/states/UploadEmptyState'>; +} +declare module 'box-react-ui/lib/icons/states/UploadFilePaywallState.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/states/UploadFilePaywallState'>; +} +declare module 'box-react-ui/lib/icons/states/UploadStartState.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/states/UploadStartState'>; +} +declare module 'box-react-ui/lib/icons/states/UploadSuccessState.js' { + declare module.exports: $Exports<'box-react-ui/lib/icons/states/UploadSuccessState'>; +} +declare module 'box-react-ui/lib/styles/variables.js' { + declare module.exports: $Exports<'box-react-ui/lib/styles/variables'>; +} +declare module 'box-react-ui/lib/utils/datetime.js' { + declare module.exports: $Exports<'box-react-ui/lib/utils/datetime'>; +} +declare module 'box-react-ui/lib/utils/getFileSize.js' { + declare module.exports: $Exports<'box-react-ui/lib/utils/getFileSize'>; +} +declare module 'box-react-ui/lib/utils/keys.js' { + declare module.exports: $Exports<'box-react-ui/lib/utils/keys'>; +} +declare module 'box-react-ui/lib/utils/parseCSV.js' { + declare module.exports: $Exports<'box-react-ui/lib/utils/parseCSV'>; +} diff --git a/flow-typed/npm/form-serialize_vx.x.x.js b/flow-typed/npm/form-serialize_vx.x.x.js new file mode 100644 index 000000000..344607410 --- /dev/null +++ b/flow-typed/npm/form-serialize_vx.x.x.js @@ -0,0 +1,38 @@ +// flow-typed signature: 5cf2b87782ae98310bd39dcb5b9dbf28 +// flow-typed version: <>/form-serialize_v^0.7.2/flow_v0.79.0 + +/** + * This is an autogenerated libdef stub for: + * + * 'form-serialize' + * + * Fill this stub out by replacing all the `any` types. + * + * Once filled out, we encourage you to share your work with the + * community by sending a pull request to: + * https://github.com/flowtype/flow-typed + */ + +declare module 'form-serialize' { + declare module.exports: any; +} + +/** + * We include stubs for each file inside this npm package in case you need to + * require those files directly. Feel free to delete any files that aren't + * needed. + */ +declare module 'form-serialize/test/index' { + declare module.exports: any; +} + +// Filename aliases +declare module 'form-serialize/index' { + declare module.exports: $Exports<'form-serialize'>; +} +declare module 'form-serialize/index.js' { + declare module.exports: $Exports<'form-serialize'>; +} +declare module 'form-serialize/test/index.js' { + declare module.exports: $Exports<'form-serialize/test/index'>; +} diff --git a/flow-typed/npm/lodash_v4.x.x.js b/flow-typed/npm/lodash_v4.x.x.js new file mode 100644 index 000000000..0ee52940b --- /dev/null +++ b/flow-typed/npm/lodash_v4.x.x.js @@ -0,0 +1,6086 @@ +// flow-typed signature: 911f4ab10b9a871625482b7b6622b76b +// flow-typed version: a0e86fa7fb/lodash_v4.x.x/flow_>=v0.63.x + +declare module "lodash" { + declare type __CurriedFunction1 = (...r: [AA]) => R; + declare type CurriedFunction1 = __CurriedFunction1; + + declare type __CurriedFunction2 = (( + ...r: [AA] + ) => CurriedFunction1) & + ((...r: [AA, BB]) => R); + declare type CurriedFunction2 = __CurriedFunction2; + + declare type __CurriedFunction3 = (( + ...r: [AA] + ) => CurriedFunction2) & + ((...r: [AA, BB]) => CurriedFunction1) & + ((...r: [AA, BB, CC]) => R); + declare type CurriedFunction3 = __CurriedFunction3< + A, + B, + C, + R, + *, + *, + * + >; + + declare type __CurriedFunction4< + A, + B, + C, + D, + R, + AA: A, + BB: B, + CC: C, + DD: D + > = ((...r: [AA]) => CurriedFunction3) & + ((...r: [AA, BB]) => CurriedFunction2) & + ((...r: [AA, BB, CC]) => CurriedFunction1) & + ((...r: [AA, BB, CC, DD]) => R); + declare type CurriedFunction4 = __CurriedFunction4< + A, + B, + C, + D, + R, + *, + *, + *, + * + >; + + declare type __CurriedFunction5< + A, + B, + C, + D, + E, + R, + AA: A, + BB: B, + CC: C, + DD: D, + EE: E + > = ((...r: [AA]) => CurriedFunction4) & + ((...r: [AA, BB]) => CurriedFunction3) & + ((...r: [AA, BB, CC]) => CurriedFunction2) & + ((...r: [AA, BB, CC, DD]) => CurriedFunction1) & + ((...r: [AA, BB, CC, DD, EE]) => R); + declare type CurriedFunction5 = __CurriedFunction5< + A, + B, + C, + D, + E, + R, + *, + *, + *, + *, + * + >; + + declare type __CurriedFunction6< + A, + B, + C, + D, + E, + F, + R, + AA: A, + BB: B, + CC: C, + DD: D, + EE: E, + FF: F + > = ((...r: [AA]) => CurriedFunction5) & + ((...r: [AA, BB]) => CurriedFunction4) & + ((...r: [AA, BB, CC]) => CurriedFunction3) & + ((...r: [AA, BB, CC, DD]) => CurriedFunction2) & + ((...r: [AA, BB, CC, DD, EE]) => CurriedFunction1) & + ((...r: [AA, BB, CC, DD, EE, FF]) => R); + declare type CurriedFunction6 = __CurriedFunction6< + A, + B, + C, + D, + E, + F, + R, + *, + *, + *, + *, + *, + * + >; + + declare type Curry = (((...r: [A]) => R) => CurriedFunction1) & + (((...r: [A, B]) => R) => CurriedFunction2) & + (((...r: [A, B, C]) => R) => CurriedFunction3) & + (( + (...r: [A, B, C, D]) => R + ) => CurriedFunction4) & + (( + (...r: [A, B, C, D, E]) => R + ) => CurriedFunction5) & + (( + (...r: [A, B, C, D, E, F]) => R + ) => CurriedFunction6); + + declare type UnaryFn = (a: A) => R; + + declare type TemplateSettings = { + escape?: RegExp, + evaluate?: RegExp, + imports?: Object, + interpolate?: RegExp, + variable?: string + }; + + declare type TruncateOptions = { + length?: number, + omission?: string, + separator?: RegExp | string + }; + + declare type DebounceOptions = { + leading?: boolean, + maxWait?: number, + trailing?: boolean + }; + + declare type ThrottleOptions = { + leading?: boolean, + trailing?: boolean + }; + + declare type NestedArray = Array>; + + declare type matchesIterateeShorthand = Object; + declare type matchesPropertyIterateeShorthand = [string, any]; + declare type propertyIterateeShorthand = string; + + declare type OPredicate = + | ((value: A, key: string, object: O) => any) + | matchesIterateeShorthand + | matchesPropertyIterateeShorthand + | propertyIterateeShorthand; + + declare type OIterateeWithResult = + | Object + | string + | ((value: V, key: string, object: O) => R); + declare type OIteratee = OIterateeWithResult; + declare type OFlatMapIteratee = OIterateeWithResult>; + + declare type Predicate = + | ((value: T, index: number, array: Array) => any) + | matchesIterateeShorthand + | matchesPropertyIterateeShorthand + | propertyIterateeShorthand; + + declare type _ValueOnlyIteratee = (value: T) => mixed; + declare type ValueOnlyIteratee = _ValueOnlyIteratee | string; + declare type _Iteratee = ( + item: T, + index: number, + array: ?Array + ) => mixed; + declare type Iteratee = _Iteratee | Object | string; + declare type FlatMapIteratee = + | ((item: T, index: number, array: ?$ReadOnlyArray) => Array) + | Object + | string; + declare type Comparator = (item: T, item2: T) => boolean; + + declare type MapIterator = + | ((item: T, index: number, array: Array) => U) + | propertyIterateeShorthand; + + declare type ReadOnlyMapIterator = + | ((item: T, index: number, array: $ReadOnlyArray) => U) + | propertyIterateeShorthand; + + declare type OMapIterator = + | ((item: T, key: string, object: O) => U) + | propertyIterateeShorthand; + + declare class Lodash { + // Array + chunk(array?: ?Array, size?: ?number): Array>; + compact(array?: ?Array): Array; + concat( + base?: ?$ReadOnlyArray, + ...elements: Array + ): Array; + difference( + array?: ?$ReadOnlyArray, + ...values: Array> + ): Array; + differenceBy( + array?: ?$ReadOnlyArray, + values?: ?$ReadOnlyArray, + iteratee?: ?ValueOnlyIteratee + ): T[]; + differenceWith( + array?: ?$ReadOnlyArray, + values?: ?$ReadOnlyArray, + comparator?: ?Comparator + ): T[]; + drop(array?: ?Array, n?: ?number): Array; + dropRight(array?: ?Array, n?: ?number): Array; + dropRightWhile(array?: ?Array, predicate?: ?Predicate): Array; + dropWhile(array?: ?Array, predicate?: ?Predicate): Array; + fill( + array?: ?Array, + value?: ?U, + start?: ?number, + end?: ?number + ): Array; + findIndex( + array: $ReadOnlyArray, + predicate?: ?Predicate, + fromIndex?: ?number + ): number; + findIndex( + array: void | null, + predicate?: ?Predicate, + fromIndex?: ?number + ): -1; + findLastIndex( + array: $ReadOnlyArray, + predicate?: ?Predicate, + fromIndex?: ?number + ): number; + findLastIndex( + array: void | null, + predicate?: ?Predicate, + fromIndex?: ?number + ): -1; + // alias of _.head + first(array: ?$ReadOnlyArray): T; + flatten(array?: ?Array | X>): Array; + flattenDeep(array?: ?(any[])): Array; + flattenDepth(array?: ?(any[]), depth?: ?number): any[]; + fromPairs(pairs?: ?Array<[A, B]>): { [key: A]: B }; + head(array: ?$ReadOnlyArray): T; + indexOf(array: Array, value: T, fromIndex?: number): number; + indexOf(array: void | null, value?: ?T, fromIndex?: ?number): -1; + initial(array: ?Array): Array; + intersection(...arrays?: Array<$ReadOnlyArray>): Array; + //Workaround until (...parameter: T, parameter2: U) works + intersectionBy( + a1?: ?$ReadOnlyArray, + iteratee?: ?ValueOnlyIteratee + ): Array; + intersectionBy( + a1?: ?$ReadOnlyArray, + a2?: ?$ReadOnlyArray, + iteratee?: ?ValueOnlyIteratee + ): Array; + intersectionBy( + a1?: ?$ReadOnlyArray, + a2?: ?$ReadOnlyArray, + a3?: ?$ReadOnlyArray, + iteratee?: ?ValueOnlyIteratee + ): Array; + intersectionBy( + a1?: ?$ReadOnlyArray, + a2?: ?$ReadOnlyArray, + a3?: ?$ReadOnlyArray, + a4?: ?$ReadOnlyArray, + iteratee?: ?ValueOnlyIteratee + ): Array; + //Workaround until (...parameter: T, parameter2: U) works + intersectionWith( + a1?: ?$ReadOnlyArray, + comparator?: ?Comparator + ): Array; + intersectionWith( + a1?: ?$ReadOnlyArray, + a2?: ?$ReadOnlyArray, + comparator?: ?Comparator + ): Array; + intersectionWith( + a1?: ?$ReadOnlyArray, + a2?: ?$ReadOnlyArray, + a3?: ?$ReadOnlyArray, + comparator?: ?Comparator + ): Array; + intersectionWith( + a1?: ?$ReadOnlyArray, + a2?: ?$ReadOnlyArray, + a3?: ?$ReadOnlyArray, + a4?: ?$ReadOnlyArray, + comparator?: ?Comparator + ): Array; + join(array: Array, separator?: ?string): string; + join(array: void | null, separator?: ?string): ""; + last(array: ?$ReadOnlyArray): T; + lastIndexOf(array: Array, value?: ?T, fromIndex?: ?number): number; + lastIndexOf(array: void | null, value?: ?T, fromIndex?: ?number): -1; + nth(array: T[], n?: ?number): T; + nth(array: void | null, n?: ?number): void; + pull(array: Array, ...values?: Array): Array; + pull(array: T, ...values?: Array): T; + pullAll(array: Array, values?: ?Array): Array; + pullAll(array: T, values?: ?Array): T; + pullAllBy( + array: Array, + values?: ?Array, + iteratee?: ?ValueOnlyIteratee + ): Array; + pullAllBy( + array: T, + values?: ?Array, + iteratee?: ?ValueOnlyIteratee + ): T; + pullAllWith(array: T[], values?: ?(T[]), comparator?: ?Function): T[]; + pullAllWith( + array: T, + values?: ?Array, + comparator?: ?Function + ): T; + pullAt(array?: ?Array, ...indexed?: Array): Array; + pullAt(array?: ?Array, indexed?: ?Array): Array; + remove(array?: ?Array, predicate?: ?Predicate): Array; + reverse(array: Array): Array; + reverse(array: T): T; + slice( + array?: ?$ReadOnlyArray, + start?: ?number, + end?: ?number + ): Array; + sortedIndex(array: Array, value: T): number; + sortedIndex(array: void | null, value: ?T): 0; + sortedIndexBy( + array: Array, + value?: ?T, + iteratee?: ?ValueOnlyIteratee + ): number; + sortedIndexBy( + array: void | null, + value?: ?T, + iteratee?: ?ValueOnlyIteratee + ): 0; + sortedIndexOf(array: Array, value: T): number; + sortedIndexOf(array: void | null, value?: ?T): -1; + sortedLastIndex(array: Array, value: T): number; + sortedLastIndex(array: void | null, value?: ?T): 0; + sortedLastIndexBy( + array: Array, + value: T, + iteratee?: ValueOnlyIteratee + ): number; + sortedLastIndexBy( + array: void | null, + value?: ?T, + iteratee?: ?ValueOnlyIteratee + ): 0; + sortedLastIndexOf(array: Array, value: T): number; + sortedLastIndexOf(array: void | null, value?: ?T): -1; + sortedUniq(array?: ?Array): Array; + sortedUniqBy( + array?: ?Array, + iteratee?: ?ValueOnlyIteratee + ): Array; + tail(array?: ?Array): Array; + take(array?: ?Array, n?: ?number): Array; + takeRight(array?: ?Array, n?: ?number): Array; + takeRightWhile(array?: ?Array, predicate?: ?Predicate): Array; + takeWhile(array?: ?Array, predicate?: ?Predicate): Array; + union(...arrays?: Array<$ReadOnlyArray>): Array; + //Workaround until (...parameter: T, parameter2: U) works + unionBy( + a1?: ?$ReadOnlyArray, + iteratee?: ?ValueOnlyIteratee + ): Array; + unionBy( + a1?: ?$ReadOnlyArray, + a2: $ReadOnlyArray, + iteratee?: ValueOnlyIteratee + ): Array; + unionBy( + a1: $ReadOnlyArray, + a2: $ReadOnlyArray, + a3: $ReadOnlyArray, + iteratee?: ValueOnlyIteratee + ): Array; + unionBy( + a1: $ReadOnlyArray, + a2: $ReadOnlyArray, + a3: $ReadOnlyArray, + a4: $ReadOnlyArray, + iteratee?: ValueOnlyIteratee + ): Array; + //Workaround until (...parameter: T, parameter2: U) works + unionWith(a1?: ?Array, comparator?: ?Comparator): Array; + unionWith( + a1: $ReadOnlyArray, + a2: $ReadOnlyArray, + comparator?: Comparator + ): Array; + unionWith( + a1: $ReadOnlyArray, + a2: $ReadOnlyArray, + a3: $ReadOnlyArray, + comparator?: Comparator + ): Array; + unionWith( + a1: $ReadOnlyArray, + a2: $ReadOnlyArray, + a3: $ReadOnlyArray, + a4: $ReadOnlyArray, + comparator?: Comparator + ): Array; + uniq(array?: ?Array): Array; + uniqBy(array?: ?Array, iteratee?: ?ValueOnlyIteratee): Array; + uniqWith(array?: ?Array, comparator?: ?Comparator): Array; + unzip(array?: ?Array): Array; + unzipWith(array: ?Array, iteratee?: ?Iteratee): Array; + without(array?: ?$ReadOnlyArray, ...values?: Array): Array; + xor(...array: Array>): Array; + //Workaround until (...parameter: T, parameter2: U) works + xorBy(a1?: ?Array, iteratee?: ?ValueOnlyIteratee): Array; + xorBy( + a1: Array, + a2: Array, + iteratee?: ValueOnlyIteratee + ): Array; + xorBy( + a1: Array, + a2: Array, + a3: Array, + iteratee?: ValueOnlyIteratee + ): Array; + xorBy( + a1: Array, + a2: Array, + a3: Array, + a4: Array, + iteratee?: ValueOnlyIteratee + ): Array; + //Workaround until (...parameter: T, parameter2: U) works + xorWith(a1?: ?Array, comparator?: ?Comparator): Array; + xorWith( + a1: Array, + a2: Array, + comparator?: Comparator + ): Array; + xorWith( + a1: Array, + a2: Array, + a3: Array, + comparator?: Comparator + ): Array; + xorWith( + a1: Array, + a2: Array, + a3: Array, + a4: Array, + comparator?: Comparator + ): Array; + zip(a1?: ?(A[]), a2?: ?(B[])): Array<[A, B]>; + zip(a1: A[], a2: B[], a3: C[]): Array<[A, B, C]>; + zip(a1: A[], a2: B[], a3: C[], a4: D[]): Array<[A, B, C, D]>; + zip( + a1: A[], + a2: B[], + a3: C[], + a4: D[], + a5: E[] + ): Array<[A, B, C, D, E]>; + + zipObject(props: Array, values?: ?Array): { [key: K]: V }; + zipObject(props: void | null, values?: ?Array): {}; + zipObjectDeep(props: any[], values?: ?any): Object; + zipObjectDeep(props: void | null, values?: ?any): {}; + + zipWith(a1?: ?Array): Array<[A]>; + zipWith(a1: Array, iteratee: (A) => T): Array; + + zipWith(a1: Array, a2: Array): Array<[A, B]>; + zipWith( + a1: Array, + a2: Array, + iteratee: (A, B) => T + ): Array; + + zipWith( + a1: Array, + a2: Array, + a3: Array + ): Array<[A, B, C]>; + zipWith( + a1: Array, + a2: Array, + a3: Array, + iteratee: (A, B, C) => T + ): Array; + + zipWith( + a1: Array, + a2: Array, + a3: Array, + a4: Array + ): Array<[A, B, C, D]>; + zipWith( + a1: Array, + a2: Array, + a3: Array, + a4: Array, + iteratee: (A, B, C, D) => T + ): Array; + + // Collection + countBy(array: Array, iteratee?: ?ValueOnlyIteratee): Object; + countBy(array: void | null, iteratee?: ?ValueOnlyIteratee): {}; + countBy(object: T, iteratee?: ?ValueOnlyIteratee): Object; + // alias of _.forEach + each(array: $ReadOnlyArray, iteratee?: ?Iteratee): Array; + each(array: T, iteratee?: ?Iteratee): T; + each(object: T, iteratee?: ?OIteratee): T; + // alias of _.forEachRight + eachRight(array: $ReadOnlyArray, iteratee?: ?Iteratee): Array; + eachRight(array: T, iteratee?: ?Iteratee): T; + eachRight(object: T, iteratee?: OIteratee): T; + every(array?: ?$ReadOnlyArray, iteratee?: ?Iteratee): boolean; + every(object: T, iteratee?: OIteratee): boolean; + filter(array?: ?$ReadOnlyArray, predicate?: ?Predicate): Array; + filter( + object: T, + predicate?: OPredicate + ): Array; + find( + array: $ReadOnlyArray, + predicate?: ?Predicate, + fromIndex?: ?number + ): T | void; + find( + array: void | null, + predicate?: ?Predicate, + fromIndex?: ?number + ): void; + find( + object: T, + predicate?: OPredicate, + fromIndex?: number + ): V; + findLast( + array: ?$ReadOnlyArray, + predicate?: ?Predicate, + fromIndex?: ?number + ): T | void; + findLast( + object: T, + predicate?: ?OPredicate + ): V; + flatMap( + array?: ?$ReadOnlyArray, + iteratee?: ?FlatMapIteratee + ): Array; + flatMap( + object: T, + iteratee?: OFlatMapIteratee + ): Array; + flatMapDeep( + array?: ?$ReadOnlyArray, + iteratee?: ?FlatMapIteratee + ): Array; + flatMapDeep( + object: T, + iteratee?: ?OFlatMapIteratee + ): Array; + flatMapDepth( + array?: ?Array, + iteratee?: ?FlatMapIteratee, + depth?: ?number + ): Array; + flatMapDepth( + object: T, + iteratee?: OFlatMapIteratee, + depth?: number + ): Array; + forEach(array: $ReadOnlyArray, iteratee?: ?Iteratee): Array; + forEach(array: T, iteratee?: ?Iteratee): T; + forEach(object: T, iteratee?: ?OIteratee): T; + forEachRight( + array: $ReadOnlyArray, + iteratee?: ?Iteratee + ): Array; + forEachRight(array: T, iteratee?: ?Iteratee): T; + forEachRight(object: T, iteratee?: ?OIteratee): T; + groupBy( + array: $ReadOnlyArray, + iteratee?: ?ValueOnlyIteratee + ): { [key: V]: Array }; + groupBy(array: void | null, iteratee?: ?ValueOnlyIteratee): {}; + groupBy( + object: T, + iteratee?: ValueOnlyIteratee + ): { [key: V]: Array }; + includes( + array: $ReadOnlyArray, + value: T, + fromIndex?: ?number + ): boolean; + includes(array: void | null, value?: ?T, fromIndex?: ?number): false; + includes(object: T, value: any, fromIndex?: number): boolean; + includes(str: string, value: string, fromIndex?: number): boolean; + invokeMap( + array?: ?$ReadOnlyArray, + path?: ?((value: T) => Array | string) | Array | string, + ...args?: Array + ): Array; + invokeMap( + object: T, + path: ((value: any) => Array | string) | Array | string, + ...args?: Array + ): Array; + keyBy( + array: $ReadOnlyArray, + iteratee?: ?ValueOnlyIteratee + ): { [key: V]: T }; + keyBy(array: void | null, iteratee?: ?ValueOnlyIteratee<*>): {}; + keyBy( + object: T, + iteratee?: ?ValueOnlyIteratee + ): { [key: V]: A }; + map(array?: ?Array, iteratee?: ?MapIterator): Array; + map( + array: ?$ReadOnlyArray, + iteratee?: ReadOnlyMapIterator + ): Array; + map( + object: ?T, + iteratee?: OMapIterator + ): Array; + map( + str: ?string, + iteratee?: (char: string, index: number, str: string) => any + ): string; + orderBy( + array: $ReadOnlyArray, + iteratees?: ?$ReadOnlyArray> | ?string, + orders?: ?$ReadOnlyArray<"asc" | "desc"> | ?string + ): Array; + orderBy( + array: null | void, + iteratees?: ?$ReadOnlyArray> | ?string, + orders?: ?$ReadOnlyArray<"asc" | "desc"> | ?string + ): Array; + orderBy( + object: T, + iteratees?: $ReadOnlyArray> | string, + orders?: $ReadOnlyArray<"asc" | "desc"> | string + ): Array; + partition( + array?: ?Array, + predicate?: ?Predicate + ): [Array, Array]; + partition( + object: T, + predicate?: OPredicate + ): [Array, Array]; + reduce( + array: $ReadOnlyArray, + iteratee?: ( + accumulator: U, + value: T, + index: number, + array: ?Array + ) => U, + accumulator?: U + ): U; + reduce( + array: void | null, + iteratee?: ?( + accumulator: U, + value: T, + index: number, + array: ?Array + ) => U, + accumulator?: ?U + ): void | null; + reduce( + object: T, + iteratee?: (accumulator: U, value: any, key: string, object: T) => U, + accumulator?: U + ): U; + reduceRight( + array: void | null, + iteratee?: ?( + accumulator: U, + value: T, + index: number, + array: ?Array + ) => U, + accumulator?: ?U + ): void | null; + reduceRight( + array: $ReadOnlyArray, + iteratee?: ?( + accumulator: U, + value: T, + index: number, + array: ?Array + ) => U, + accumulator?: ?U + ): U; + reduceRight( + object: T, + iteratee?: ?(accumulator: U, value: any, key: string, object: T) => U, + accumulator?: ?U + ): U; + reject(array: ?$ReadOnlyArray, predicate?: Predicate): Array; + reject( + object?: ?T, + predicate?: ?OPredicate + ): Array; + sample(array: ?Array): T; + sample(object: T): V; + sampleSize(array?: ?Array, n?: ?number): Array; + sampleSize(object: T, n?: number): Array; + shuffle(array: ?Array): Array; + shuffle(object: T): Array; + size(collection: $ReadOnlyArray | Object | string): number; + some(array: ?$ReadOnlyArray, predicate?: Predicate): boolean; + some(array: void | null, predicate?: ?Predicate): false; + some( + object?: ?T, + predicate?: OPredicate + ): boolean; + sortBy( + array: ?$ReadOnlyArray, + ...iteratees?: $ReadOnlyArray> + ): Array; + sortBy( + array: ?$ReadOnlyArray, + iteratees?: $ReadOnlyArray> + ): Array; + sortBy( + object: T, + ...iteratees?: Array> + ): Array; + sortBy( + object: T, + iteratees?: $ReadOnlyArray> + ): Array; + + // Date + now(): number; + + // Function + after(n: number, fn: Function): Function; + ary(func: Function, n?: number): Function; + before(n: number, fn: Function): Function; + bind(func: Function, thisArg: any, ...partials: Array): Function; + bindKey(obj?: ?Object, key?: ?string, ...partials?: Array): Function; + curry: Curry; + curry(func: Function, arity?: number): Function; + curryRight(func: Function, arity?: number): Function; + debounce(func: F, wait?: number, options?: DebounceOptions): F; + defer(func: Function, ...args?: Array): TimeoutID; + delay(func: Function, wait: number, ...args?: Array): TimeoutID; + flip(func: Function): Function; + memoize(func: F, resolver?: Function): F; + negate(predicate: Function): Function; + once(func: Function): Function; + overArgs(func?: ?Function, ...transforms?: Array): Function; + overArgs(func?: ?Function, transforms?: ?Array): Function; + partial(func: Function, ...partials: any[]): Function; + partialRight(func: Function, ...partials: Array): Function; + partialRight(func: Function, partials: Array): Function; + rearg(func: Function, ...indexes: Array): Function; + rearg(func: Function, indexes: Array): Function; + rest(func: Function, start?: number): Function; + spread(func: Function): Function; + throttle( + func: Function, + wait?: number, + options?: ThrottleOptions + ): Function; + unary(func: Function): Function; + wrap(value?: any, wrapper?: ?Function): Function; + + // Lang + castArray(value: *): any[]; + clone(value: T): T; + cloneDeep(value: T): T; + cloneDeepWith( + value: T, + customizer?: ?(value: T, key: number | string, object: T, stack: any) => U + ): U; + cloneWith( + value: T, + customizer?: ?(value: T, key: number | string, object: T, stack: any) => U + ): U; + conformsTo( + source: T, + predicates: T & { [key: string]: (x: any) => boolean } + ): boolean; + eq(value: any, other: any): boolean; + gt(value: any, other: any): boolean; + gte(value: any, other: any): boolean; + isArguments(value: void | null): false; + isArguments(value: any): boolean; + isArray(value: Array): true; + isArray(value: any): false; + isArrayBuffer(value: ArrayBuffer): true; + isArrayBuffer(value: any): false; + isArrayLike(value: Array | string | { length: number }): true; + isArrayLike(value: any): false; + isArrayLikeObject(value: { length: number } | Array): true; + isArrayLikeObject(value: any): false; + isBoolean(value: boolean): true; + isBoolean(value: any): false; + isBuffer(value: void | null): false; + isBuffer(value: any): boolean; + isDate(value: Date): true; + isDate(value: any): false; + isElement(value: Element): true; + isElement(value: any): false; + isEmpty(value: void | null | "" | {} | [] | number | boolean): true; + isEmpty(value: any): boolean; + isEqual(value: any, other: any): boolean; + isEqualWith( + value?: ?T, + other?: ?U, + customizer?: ?( + objValue: any, + otherValue: any, + key: number | string, + object: T, + other: U, + stack: any + ) => boolean | void + ): boolean; + isError(value: Error): true; + isError(value: any): false; + isFinite(value: number): boolean; + isFinite(value: any): false; + isFunction(value: Function): true; + isFunction(value: any): false; + isInteger(value: number): boolean; + isInteger(value: any): false; + isLength(value: void | null): false; + isLength(value: any): boolean; + isMap(value: Map): true; + isMap(value: any): false; + isMatch(object?: ?Object, source?: ?Object): boolean; + isMatchWith( + object?: ?T, + source?: ?U, + customizer?: ?( + objValue: any, + srcValue: any, + key: number | string, + object: T, + source: U + ) => boolean | void + ): boolean; + isNaN(value: number): boolean; + isNaN(value: any): false; + isNative(value: number | string | void | null | Object): false; + isNative(value: any): boolean; + isNil(value: void | null): true; + isNil(value: any): false; + isNull(value: null): true; + isNull(value: any): false; + isNumber(value: number): true; + isNumber(value: any): false; + isObject(value: Object): true; + isObject(value: any): false; + isObjectLike(value: void | null): false; + isObjectLike(value: any): boolean; + isPlainObject(value: Object): true; + isPlainObject(value: any): false; + isRegExp(value: RegExp): true; + isRegExp(value: any): false; + isSafeInteger(value: number): boolean; + isSafeInteger(value: any): false; + isSet(value: Set): true; + isSet(value: any): false; + isString(value: string): true; + isString(value: any): false; + isSymbol(value: Symbol): true; + isSymbol(value: any): false; + isTypedArray(value: $TypedArray): true; + isTypedArray(value: any): false; + isUndefined(value: void): true; + isUndefined(value: any): false; + isWeakMap(value: WeakMap): true; + isWeakMap(value: any): false; + isWeakSet(value: WeakSet): true; + isWeakSet(value: any): false; + lt(value: any, other: any): boolean; + lte(value: any, other: any): boolean; + toArray(value: any): Array; + toFinite(value: void | null): 0; + toFinite(value: any): number; + toInteger(value: void | null): 0; + toInteger(value: any): number; + toLength(value: void | null): 0; + toLength(value: any): number; + toNumber(value: void | null): 0; + toNumber(value: any): number; + toPlainObject(value: any): Object; + toSafeInteger(value: void | null): 0; + toSafeInteger(value: any): number; + toString(value: void | null): ""; + toString(value: any): string; + + // Math + add(augend: number, addend: number): number; + ceil(number: number, precision?: number): number; + divide(dividend: number, divisor: number): number; + floor(number: number, precision?: number): number; + max(array: ?Array): T; + maxBy(array: ?$ReadOnlyArray, iteratee?: Iteratee): T; + mean(array: Array<*>): number; + meanBy(array: Array, iteratee?: Iteratee): number; + min(array: ?Array): T; + minBy(array: ?$ReadOnlyArray, iteratee?: Iteratee): T; + multiply(multiplier: number, multiplicand: number): number; + round(number: number, precision?: number): number; + subtract(minuend: number, subtrahend: number): number; + sum(array: Array<*>): number; + sumBy(array: Array, iteratee?: Iteratee): number; + + // number + clamp(number?: number, lower?: ?number, upper?: ?number): number; + clamp(number: ?number, lower?: ?number, upper?: ?number): 0; + inRange(number: number, start?: number, end: number): boolean; + random(lower?: number, upper?: number, floating?: boolean): number; + + // Object + assign(object?: ?Object, ...sources?: Array): Object; + assignIn(): {}; + assignIn(a: A, b: B): A & B; + assignIn(a: A, b: B, c: C): A & B & C; + assignIn(a: A, b: B, c: C, d: D): A & B & C & D; + assignIn(a: A, b: B, c: C, d: D, e: E): A & B & C & D & E; + assignInWith(): {}; + assignInWith( + object: T, + s1: A, + customizer?: ( + objValue: any, + srcValue: any, + key: string, + object: T, + source: A + ) => any | void + ): Object; + assignInWith( + object: T, + s1: A, + s2: B, + customizer?: ( + objValue: any, + srcValue: any, + key: string, + object: T, + source: A | B + ) => any | void + ): Object; + assignInWith( + object: T, + s1: A, + s2: B, + s3: C, + customizer?: ( + objValue: any, + srcValue: any, + key: string, + object: T, + source: A | B | C + ) => any | void + ): Object; + assignInWith( + object: T, + s1: A, + s2: B, + s3: C, + s4: D, + customizer?: ( + objValue: any, + srcValue: any, + key: string, + object: T, + source: A | B | C | D + ) => any | void + ): Object; + assignWith(): {}; + assignWith( + object: T, + s1: A, + customizer?: ( + objValue: any, + srcValue: any, + key: string, + object: T, + source: A + ) => any | void + ): Object; + assignWith( + object: T, + s1: A, + s2: B, + customizer?: ( + objValue: any, + srcValue: any, + key: string, + object: T, + source: A | B + ) => any | void + ): Object; + assignWith( + object: T, + s1: A, + s2: B, + s3: C, + customizer?: ( + objValue: any, + srcValue: any, + key: string, + object: T, + source: A | B | C + ) => any | void + ): Object; + assignWith( + object: T, + s1: A, + s2: B, + s3: C, + s4: D, + customizer?: ( + objValue: any, + srcValue: any, + key: string, + object: T, + source: A | B | C | D + ) => any | void + ): Object; + at(object?: ?Object, ...paths: Array): Array; + at(object?: ?Object, paths: Array): Array; + create(prototype: T, properties: Object): $Supertype; + create(prototype: any, properties: void | null): {}; + defaults(object?: ?Object, ...sources?: Array): Object; + defaultsDeep(object?: ?Object, ...sources?: Array): Object; + // alias for _.toPairs + entries(object?: ?Object): Array<[string, any]>; + // alias for _.toPairsIn + entriesIn(object?: ?Object): Array<[string, any]>; + // alias for _.assignIn + extend(a?: ?A, b?: ?B): A & B; + extend(a: A, b: B, c: C): A & B & C; + extend(a: A, b: B, c: C, d: D): A & B & C & D; + extend(a: A, b: B, c: C, d: D, e: E): A & B & C & D & E; + // alias for _.assignInWith + extendWith( + object?: ?T, + s1?: ?A, + customizer?: ?( + objValue: any, + srcValue: any, + key: string, + object: T, + source: A + ) => any | void + ): Object; + extendWith( + object: T, + s1: A, + s2: B, + customizer?: ( + objValue: any, + srcValue: any, + key: string, + object: T, + source: A | B + ) => any | void + ): Object; + extendWith( + object: T, + s1: A, + s2: B, + s3: C, + customizer?: ( + objValue: any, + srcValue: any, + key: string, + object: T, + source: A | B | C + ) => any | void + ): Object; + extendWith( + object: T, + s1: A, + s2: B, + s3: C, + s4: D, + customizer?: ( + objValue: any, + srcValue: any, + key: string, + object: T, + source: A | B | C | D + ) => any | void + ): Object; + findKey( + object: T, + predicate?: ?OPredicate + ): string | void; + findKey( + object: void | null, + predicate?: ?OPredicate + ): void; + findLastKey( + object: T, + predicate?: ?OPredicate + ): string | void; + findLastKey( + object: void | null, + predicate?: ?OPredicate + ): void; + forIn(object: Object, iteratee?: ?OIteratee<*>): Object; + forIn(object: void | null, iteratee?: ?OIteratee<*>): null; + forInRight(object: Object, iteratee?: ?OIteratee<*>): Object; + forInRight(object: void | null, iteratee?: ?OIteratee<*>): null; + forOwn(object: Object, iteratee?: ?OIteratee<*>): Object; + forOwn(object: void | null, iteratee?: ?OIteratee<*>): null; + forOwnRight(object: Object, iteratee?: ?OIteratee<*>): Object; + forOwnRight(object: void | null, iteratee?: ?OIteratee<*>): null; + functions(object?: ?Object): Array; + functionsIn(object?: ?Object): Array; + get( + object?: ?Object | ?$ReadOnlyArray | void | null, + path?: ?$ReadOnlyArray | string | number, + defaultValue?: any + ): any; + has(object: Object, path: Array | string): boolean; + has(object: Object, path: void | null): false; + has(object: void | null, path?: ?Array | ?string): false; + hasIn(object: Object, path: Array | string): boolean; + hasIn(object: Object, path: void | null): false; + hasIn(object: void | null, path?: ?Array | ?string): false; + invert(object: Object, multiVal?: ?boolean): Object; + invert(object: void | null, multiVal?: ?boolean): {}; + invertBy(object: Object, iteratee?: ?Function): Object; + invertBy(object: void | null, iteratee?: ?Function): {}; + invoke( + object?: ?Object, + path?: ?Array | string, + ...args?: Array + ): any; + keys(object?: ?{ [key: K]: any }): Array; + keys(object?: ?Object): Array; + keysIn(object?: ?Object): Array; + mapKeys(object: Object, iteratee?: ?OIteratee<*>): Object; + mapKeys(object: void | null, iteratee?: ?OIteratee<*>): {}; + mapValues(object: Object, iteratee?: ?OIteratee<*>): Object; + mapValues(object: void | null, iteratee?: ?OIteratee<*>): {}; + merge(object?: ?Object, ...sources?: Array): Object; + mergeWith(): {}; + mergeWith( + object: T, + customizer?: ( + objValue: any, + srcValue: any, + key: string, + object: T, + source: A + ) => any | void + ): Object; + mergeWith( + object: T, + s1: A, + s2: B, + customizer?: ( + objValue: any, + srcValue: any, + key: string, + object: T, + source: A | B + ) => any | void + ): Object; + mergeWith( + object: T, + s1: A, + s2: B, + s3: C, + customizer?: ( + objValue: any, + srcValue: any, + key: string, + object: T, + source: A | B | C + ) => any | void + ): Object; + mergeWith( + object: T, + s1: A, + s2: B, + s3: C, + s4: D, + customizer?: ( + objValue: any, + srcValue: any, + key: string, + object: T, + source: A | B | C | D + ) => any | void + ): Object; + omit(object?: ?Object, ...props: Array): Object; + omit(object?: ?Object, props: Array): Object; + omitBy( + object: T, + predicate?: ?OPredicate + ): Object; + omitBy(object: void | null, predicate?: ?OPredicate): {}; + pick(object?: ?Object, ...props: Array): Object; + pick(object?: ?Object, props: Array): Object; + pickBy( + object: T, + predicate?: ?OPredicate + ): Object; + pickBy(object: void | null, predicate?: ?OPredicate): {}; + result( + object?: ?Object, + path?: ?Array | string, + defaultValue?: any + ): any; + set(object: Object, path?: ?Array | string, value: any): Object; + set( + object: T, + path?: ?Array | string, + value?: ?any + ): T; + setWith( + object: T, + path?: ?Array | string, + value: any, + customizer?: (nsValue: any, key: string, nsObject: T) => any + ): Object; + setWith( + object: T, + path?: ?Array | string, + value?: ?any, + customizer?: ?(nsValue: any, key: string, nsObject: T) => any + ): T; + toPairs(object?: ?Object | Array<*>): Array<[string, any]>; + toPairsIn(object?: ?Object): Array<[string, any]>; + transform( + collection: Object | $ReadOnlyArray, + iteratee?: ?OIteratee<*>, + accumulator?: any + ): any; + transform( + collection: void | null, + iteratee?: ?OIteratee<*>, + accumulator?: ?any + ): {}; + unset(object: Object, path?: ?Array | ?string): boolean; + unset(object: void | null, path?: ?Array | ?string): true; + update(object: Object, path: string[] | string, updater: Function): Object; + update( + object: T, + path?: ?(string[]) | ?string, + updater?: ?Function + ): T; + updateWith( + object: Object, + path?: ?(string[]) | ?string, + updater?: ?Function, + customizer?: ?Function + ): Object; + updateWith( + object: T, + path?: ?(string[]) | ?string, + updater?: ?Function, + customizer?: ?Function + ): T; + values(object?: ?Object): Array; + valuesIn(object?: ?Object): Array; + + // Seq + // harder to read, but this is _() + (value: any): any; + chain(value: T): any; + tap(value: T, interceptor: (value: T) => any): T; + thru(value: T1, interceptor: (value: T1) => T2): T2; + // TODO: _.prototype.* + + // String + camelCase(string: string): string; + camelCase(string: void | null): ""; + capitalize(string: string): string; + capitalize(string: void | null): ""; + deburr(string: string): string; + deburr(string: void | null): ""; + endsWith(string: string, target?: string, position?: ?number): boolean; + endsWith(string: void | null, target?: ?string, position?: ?number): false; + escape(string: string): string; + escape(string: void | null): ""; + escapeRegExp(string: string): string; + escapeRegExp(string: void | null): ""; + kebabCase(string: string): string; + kebabCase(string: void | null): ""; + lowerCase(string: string): string; + lowerCase(string: void | null): ""; + lowerFirst(string: string): string; + lowerFirst(string: void | null): ""; + pad(string?: ?string, length?: ?number, chars?: ?string): string; + padEnd(string?: ?string, length?: ?number, chars?: ?string): string; + padStart(string?: ?string, length?: ?number, chars?: ?string): string; + parseInt(string: string, radix?: ?number): number; + repeat(string: string, n?: ?number): string; + repeat(string: void | null, n?: ?number): ""; + replace( + string: string, + pattern: RegExp | string, + replacement: ((string: string) => string) | string + ): string; + replace( + string: void | null, + pattern?: ?RegExp | ?string, + replacement: ?((string: string) => string) | ?string + ): ""; + snakeCase(string: string): string; + snakeCase(string: void | null): ""; + split( + string?: ?string, + separator?: ?RegExp | ?string, + limit?: ?number + ): Array; + startCase(string: string): string; + startCase(string: void | null): ""; + startsWith(string: string, target?: string, position?: number): boolean; + startsWith( + string: void | null, + target?: ?string, + position?: ?number + ): false; + template(string?: ?string, options?: ?TemplateSettings): Function; + toLower(string: string): string; + toLower(string: void | null): ""; + toUpper(string: string): string; + toUpper(string: void | null): ""; + trim(string: string, chars?: string): string; + trim(string: void | null, chars?: ?string): ""; + trimEnd(string: string, chars?: ?string): string; + trimEnd(string: void | null, chars?: ?string): ""; + trimStart(string: string, chars?: ?string): string; + trimStart(string: void | null, chars?: ?string): ""; + truncate(string: string, options?: TruncateOptions): string; + truncate(string: void | null, options?: ?TruncateOptions): ""; + unescape(string: string): string; + unescape(string: void | null): ""; + upperCase(string: string): string; + upperCase(string: void | null): ""; + upperFirst(string: string): string; + upperFirst(string: void | null): ""; + words(string?: ?string, pattern?: ?RegExp | ?string): Array; + + // Util + attempt(func: Function, ...args: Array): any; + bindAll(object: Object, methodNames?: ?Array): Object; + bindAll(object: T, methodNames?: ?Array): T; + bindAll(object: Object, ...methodNames: Array): Object; + cond(pairs?: ?NestedArray): Function; + conforms(source?: ?Object): Function; + constant(value: T): () => T; + defaultTo( + value: T1, + defaultValue: T2 + ): T1; + // NaN is a number instead of its own type, otherwise it would behave like null/void + defaultTo(value: T1, defaultValue: T2): T1 | T2; + defaultTo(value: T1, defaultValue: T2): T2; + flow: $ComposeReverse & ((funcs: Array) => Function); + flowRight: $Compose & ((funcs: Array) => Function); + identity(value: T): T; + iteratee(func?: any): Function; + matches(source?: ?Object): Function; + matchesProperty(path?: ?Array | string, srcValue: any): Function; + method(path?: ?Array | string, ...args?: Array): Function; + methodOf(object?: ?Object, ...args?: Array): Function; + mixin( + object?: T, + source: Object, + options?: { chain: boolean } + ): T; + noConflict(): Lodash; + noop(...args: Array): void; + nthArg(n?: ?number): Function; + over(...iteratees: Array): Function; + over(iteratees: Array): Function; + overEvery(...predicates: Array): Function; + overEvery(predicates: Array): Function; + overSome(...predicates: Array): Function; + overSome(predicates: Array): Function; + property(path?: ?Array | string): Function; + propertyOf(object?: ?Object): Function; + range(start: number, end: number, step?: number): Array; + range(end: number, step?: number): Array; + rangeRight(start?: ?number, end?: ?number, step?: ?number): Array; + rangeRight(end?: ?number, step?: ?number): Array; + runInContext(context?: ?Object): Function; + + stubArray(): Array<*>; + stubFalse(): false; + stubObject(): {}; + stubString(): ""; + stubTrue(): true; + times(n?: ?number, ...rest?: Array): Array; + times(n: number, iteratee: (i: number) => T): Array; + toPath(value: any): Array; + uniqueId(prefix?: ?string): string; + + // Properties + VERSION: string; + templateSettings: TemplateSettings; + } + + declare module.exports: Lodash; +} + +declare module "lodash/fp" { + declare type __CurriedFunction1 = (...r: [AA]) => R; + declare type CurriedFunction1 = __CurriedFunction1; + + declare type __CurriedFunction2 = (( + ...r: [AA] + ) => CurriedFunction1) & + ((...r: [AA, BB]) => R); + declare type CurriedFunction2 = __CurriedFunction2; + + declare type __CurriedFunction3 = (( + ...r: [AA] + ) => CurriedFunction2) & + ((...r: [AA, BB]) => CurriedFunction1) & + ((...r: [AA, BB, CC]) => R); + declare type CurriedFunction3 = __CurriedFunction3< + A, + B, + C, + R, + *, + *, + * + >; + + declare type __CurriedFunction4< + A, + B, + C, + D, + R, + AA: A, + BB: B, + CC: C, + DD: D + > = ((...r: [AA]) => CurriedFunction3) & + ((...r: [AA, BB]) => CurriedFunction2) & + ((...r: [AA, BB, CC]) => CurriedFunction1) & + ((...r: [AA, BB, CC, DD]) => R); + declare type CurriedFunction4 = __CurriedFunction4< + A, + B, + C, + D, + R, + *, + *, + *, + * + >; + + declare type __CurriedFunction5< + A, + B, + C, + D, + E, + R, + AA: A, + BB: B, + CC: C, + DD: D, + EE: E + > = ((...r: [AA]) => CurriedFunction4) & + ((...r: [AA, BB]) => CurriedFunction3) & + ((...r: [AA, BB, CC]) => CurriedFunction2) & + ((...r: [AA, BB, CC, DD]) => CurriedFunction1) & + ((...r: [AA, BB, CC, DD, EE]) => R); + declare type CurriedFunction5 = __CurriedFunction5< + A, + B, + C, + D, + E, + R, + *, + *, + *, + *, + * + >; + + declare type __CurriedFunction6< + A, + B, + C, + D, + E, + F, + R, + AA: A, + BB: B, + CC: C, + DD: D, + EE: E, + FF: F + > = ((...r: [AA]) => CurriedFunction5) & + ((...r: [AA, BB]) => CurriedFunction4) & + ((...r: [AA, BB, CC]) => CurriedFunction3) & + ((...r: [AA, BB, CC, DD]) => CurriedFunction2) & + ((...r: [AA, BB, CC, DD, EE]) => CurriedFunction1) & + ((...r: [AA, BB, CC, DD, EE, FF]) => R); + declare type CurriedFunction6 = __CurriedFunction6< + A, + B, + C, + D, + E, + F, + R, + *, + *, + *, + *, + *, + * + >; + + declare type Curry = (((...r: [A]) => R) => CurriedFunction1) & + (((...r: [A, B]) => R) => CurriedFunction2) & + (((...r: [A, B, C]) => R) => CurriedFunction3) & + (( + (...r: [A, B, C, D]) => R + ) => CurriedFunction4) & + (( + (...r: [A, B, C, D, E]) => R + ) => CurriedFunction5) & + (( + (...r: [A, B, C, D, E, F]) => R + ) => CurriedFunction6); + + declare type UnaryFn = (a: A) => R; + + declare type TemplateSettings = { + escape?: RegExp, + evaluate?: RegExp, + imports?: Object, + interpolate?: RegExp, + variable?: string + }; + + declare type TruncateOptions = { + length?: number, + omission?: string, + separator?: RegExp | string + }; + + declare type DebounceOptions = { + leading?: boolean, + maxWait?: number, + trailing?: boolean + }; + + declare type ThrottleOptions = { + leading?: boolean, + trailing?: boolean + }; + + declare type NestedArray = Array>; + + declare type matchesIterateeShorthand = Object; + declare type matchesPropertyIterateeShorthand = [string, any]; + declare type propertyIterateeShorthand = string; + + declare type OPredicate = + | ((value: A) => any) + | matchesIterateeShorthand + | matchesPropertyIterateeShorthand + | propertyIterateeShorthand; + + declare type OIterateeWithResult = Object | string | ((value: V) => R); + declare type OIteratee = OIterateeWithResult; + declare type OFlatMapIteratee = OIterateeWithResult>; + + declare type Predicate = + | ((value: T) => any) + | matchesIterateeShorthand + | matchesPropertyIterateeShorthand + | propertyIterateeShorthand; + + declare type _ValueOnlyIteratee = (value: T) => mixed; + declare type ValueOnlyIteratee = _ValueOnlyIteratee | string; + declare type _Iteratee = (item: T) => mixed; + declare type Iteratee = _Iteratee | Object | string; + declare type FlatMapIteratee = + | ((item: T) => Array) + | Object + | string; + declare type Comparator = (item: T, item2: T) => boolean; + + declare type MapIterator = ((item: T) => U) | propertyIterateeShorthand; + + declare type OMapIterator = + | ((item: T) => U) + | propertyIterateeShorthand; + + declare class Lodash { + // Array + chunk(size: number): (array: Array) => Array>; + chunk(size: number, array: Array): Array>; + compact(array?: ?$ReadOnlyArray): Array; + concat | T, B: Array | U>( + base: A + ): (elements: B) => Array; + concat | T, B: Array | U>( + base: A, + elements: B + ): Array; + difference(values: $ReadOnlyArray): (array: $ReadOnlyArray) => T[]; + difference(values: $ReadOnlyArray, array: $ReadOnlyArray): T[]; + differenceBy( + iteratee: ValueOnlyIteratee + ): ((values: $ReadOnlyArray) => (array: $ReadOnlyArray) => T[]) & + ((values: $ReadOnlyArray, array: $ReadOnlyArray) => T[]); + differenceBy( + iteratee: ValueOnlyIteratee, + values: $ReadOnlyArray + ): (array: $ReadOnlyArray) => T[]; + differenceBy( + iteratee: ValueOnlyIteratee, + values: $ReadOnlyArray, + array: $ReadOnlyArray + ): T[]; + differenceWith( + comparator: Comparator + ): ((first: $ReadOnly) => (second: $ReadOnly) => T[]) & + ((first: $ReadOnly, second: $ReadOnly) => T[]); + differenceWith( + comparator: Comparator, + first: $ReadOnly + ): (second: $ReadOnly) => T[]; + differenceWith( + comparator: Comparator, + first: $ReadOnly, + second: $ReadOnly + ): T[]; + drop(n: number): (array: Array) => Array; + drop(n: number, array: Array): Array; + dropLast(n: number): (array: Array) => Array; + dropLast(n: number, array: Array): Array; + dropRight(n: number): (array: Array) => Array; + dropRight(n: number, array: Array): Array; + dropRightWhile(predicate: Predicate): (array: Array) => Array; + dropRightWhile(predicate: Predicate, array: Array): Array; + dropWhile(predicate: Predicate): (array: Array) => Array; + dropWhile(predicate: Predicate, array: Array): Array; + dropLastWhile(predicate: Predicate): (array: Array) => Array; + dropLastWhile(predicate: Predicate, array: Array): Array; + fill( + start: number + ): (( + end: number + ) => ((value: U) => (array: Array) => Array) & + ((value: U, array: Array) => Array)) & + ((end: number, value: U) => (array: Array) => Array) & + ((end: number, value: U, array: Array) => Array); + fill( + start: number, + end: number + ): ((value: U) => (array: Array) => Array) & + ((value: U, array: Array) => Array); + fill( + start: number, + end: number, + value: U + ): (array: Array) => Array; + fill( + start: number, + end: number, + value: U, + array: Array + ): Array; + findIndex(predicate: Predicate): (array: $ReadOnlyArray) => number; + findIndex(predicate: Predicate, array: $ReadOnlyArray): number; + findIndexFrom( + predicate: Predicate + ): ((fromIndex: number) => (array: $ReadOnlyArray) => number) & + ((fromIndex: number, array: $ReadOnlyArray) => number); + findIndexFrom( + predicate: Predicate, + fromIndex: number + ): (array: $ReadOnlyArray) => number; + findIndexFrom( + predicate: Predicate, + fromIndex: number, + array: $ReadOnlyArray + ): number; + findLastIndex( + predicate: Predicate + ): (array: $ReadOnlyArray) => number; + findLastIndex(predicate: Predicate, array: $ReadOnlyArray): number; + findLastIndexFrom( + predicate: Predicate + ): ((fromIndex: number) => (array: $ReadOnlyArray) => number) & + ((fromIndex: number, array: $ReadOnlyArray) => number); + findLastIndexFrom( + predicate: Predicate, + fromIndex: number + ): (array: $ReadOnlyArray) => number; + findLastIndexFrom( + predicate: Predicate, + fromIndex: number, + array: $ReadOnlyArray + ): number; + // alias of _.head + first(array: $ReadOnlyArray): T; + flatten(array: Array | X>): Array; + unnest(array: Array | X>): Array; + flattenDeep(array: any[]): Array; + flattenDepth(depth: number): (array: any[]) => any[]; + flattenDepth(depth: number, array: any[]): any[]; + fromPairs(pairs: Array<[A, B]>): { [key: A]: B }; + head(array: $ReadOnlyArray): T; + indexOf(value: T): (array: Array) => number; + indexOf(value: T, array: Array): number; + indexOfFrom( + value: T + ): ((fromIndex: number) => (array: Array) => number) & + ((fromIndex: number, array: Array) => number); + indexOfFrom(value: T, fromIndex: number): (array: Array) => number; + indexOfFrom(value: T, fromIndex: number, array: Array): number; + initial(array: Array): Array; + init(array: Array): Array; + intersection(a1: Array): (a2: Array) => Array; + intersection(a1: Array, a2: Array): Array; + intersectionBy( + iteratee: ValueOnlyIteratee + ): ((a1: Array) => (a2: Array) => Array) & + ((a1: Array, a2: Array) => Array); + intersectionBy( + iteratee: ValueOnlyIteratee, + a1: Array + ): (a2: Array) => Array; + intersectionBy( + iteratee: ValueOnlyIteratee, + a1: Array, + a2: Array + ): Array; + intersectionWith( + comparator: Comparator + ): ((a1: Array) => (a2: Array) => Array) & + ((a1: Array, a2: Array) => Array); + intersectionWith( + comparator: Comparator, + a1: Array + ): (a2: Array) => Array; + intersectionWith( + comparator: Comparator, + a1: Array, + a2: Array + ): Array; + join(separator: string): (array: Array) => string; + join(separator: string, array: Array): string; + last(array: Array): T; + lastIndexOf(value: T): (array: Array) => number; + lastIndexOf(value: T, array: Array): number; + lastIndexOfFrom( + value: T + ): ((fromIndex: number) => (array: Array) => number) & + ((fromIndex: number, array: Array) => number); + lastIndexOfFrom( + value: T, + fromIndex: number + ): (array: Array) => number; + lastIndexOfFrom(value: T, fromIndex: number, array: Array): number; + nth(n: number): (array: T[]) => T; + nth(n: number, array: T[]): T; + pull(value: T): (array: Array) => Array; + pull(value: T, array: Array): Array; + pullAll(values: Array): (array: Array) => Array; + pullAll(values: Array, array: Array): Array; + pullAllBy( + iteratee: ValueOnlyIteratee + ): ((values: Array) => (array: Array) => Array) & + ((values: Array, array: Array) => Array); + pullAllBy( + iteratee: ValueOnlyIteratee, + values: Array + ): (array: Array) => Array; + pullAllBy( + iteratee: ValueOnlyIteratee, + values: Array, + array: Array + ): Array; + pullAllWith( + comparator: Function + ): ((values: T[]) => (array: T[]) => T[]) & + ((values: T[], array: T[]) => T[]); + pullAllWith(comparator: Function, values: T[]): (array: T[]) => T[]; + pullAllWith(comparator: Function, values: T[], array: T[]): T[]; + pullAt(indexed: Array): (array: Array) => Array; + pullAt(indexed: Array, array: Array): Array; + remove(predicate: Predicate): (array: Array) => Array; + remove(predicate: Predicate, array: Array): Array; + reverse(array: Array): Array; + slice( + start: number + ): ((end: number) => (array: Array) => Array) & + ((end: number, array: Array) => Array); + slice(start: number, end: number): (array: Array) => Array; + slice(start: number, end: number, array: Array): Array; + sortedIndex(value: T): (array: Array) => number; + sortedIndex(value: T, array: Array): number; + sortedIndexBy( + iteratee: ValueOnlyIteratee + ): ((value: T) => (array: Array) => number) & + ((value: T, array: Array) => number); + sortedIndexBy( + iteratee: ValueOnlyIteratee, + value: T + ): (array: Array) => number; + sortedIndexBy( + iteratee: ValueOnlyIteratee, + value: T, + array: Array + ): number; + sortedIndexOf(value: T): (array: Array) => number; + sortedIndexOf(value: T, array: Array): number; + sortedLastIndex(value: T): (array: Array) => number; + sortedLastIndex(value: T, array: Array): number; + sortedLastIndexBy( + iteratee: ValueOnlyIteratee + ): ((value: T) => (array: Array) => number) & + ((value: T, array: Array) => number); + sortedLastIndexBy( + iteratee: ValueOnlyIteratee, + value: T + ): (array: Array) => number; + sortedLastIndexBy( + iteratee: ValueOnlyIteratee, + value: T, + array: Array + ): number; + sortedLastIndexOf(value: T): (array: Array) => number; + sortedLastIndexOf(value: T, array: Array): number; + sortedUniq(array: Array): Array; + sortedUniqBy(iteratee: ValueOnlyIteratee, array: Array): Array; + tail(array: Array): Array; + take(n: number): (array: Array) => Array; + take(n: number, array: Array): Array; + takeRight(n: number): (array: Array) => Array; + takeRight(n: number, array: Array): Array; + takeLast(n: number): (array: Array) => Array; + takeLast(n: number, array: Array): Array; + takeRightWhile(predicate: Predicate): (array: Array) => Array; + takeRightWhile(predicate: Predicate, array: Array): Array; + takeLastWhile(predicate: Predicate): (array: Array) => Array; + takeLastWhile(predicate: Predicate, array: Array): Array; + takeWhile(predicate: Predicate): (array: Array) => Array; + takeWhile(predicate: Predicate, array: Array): Array; + union(a1: Array): (a2: Array) => Array; + union(a1: Array, a2: Array): Array; + unionBy( + iteratee: ValueOnlyIteratee + ): ((a1: Array) => (a2: Array) => Array) & + ((a1: Array, a2: Array) => Array); + unionBy( + iteratee: ValueOnlyIteratee, + a1: Array + ): (a2: Array) => Array; + unionBy( + iteratee: ValueOnlyIteratee, + a1: Array, + a2: Array + ): Array; + unionWith( + comparator: Comparator + ): ((a1: Array) => (a2: Array) => Array) & + ((a1: Array, a2: Array) => Array); + unionWith( + comparator: Comparator, + a1: Array + ): (a2: Array) => Array; + unionWith( + comparator: Comparator, + a1: Array, + a2: Array + ): Array; + uniq(array: Array): Array; + uniqBy(iteratee: ValueOnlyIteratee): (array: Array) => Array; + uniqBy(iteratee: ValueOnlyIteratee, array: Array): Array; + uniqWith(comparator: Comparator): (array: Array) => Array; + uniqWith(comparator: Comparator, array: Array): Array; + unzip(array: Array): Array; + unzipWith(iteratee: Iteratee): (array: Array) => Array; + unzipWith(iteratee: Iteratee, array: Array): Array; + without(values: Array): (array: Array) => Array; + without(values: Array, array: Array): Array; + xor(a1: Array): (a2: Array) => Array; + xor(a1: Array, a2: Array): Array; + symmetricDifference(a1: Array): (a2: Array) => Array; + symmetricDifference(a1: Array, a2: Array): Array; + xorBy( + iteratee: ValueOnlyIteratee + ): ((a1: Array) => (a2: Array) => Array) & + ((a1: Array, a2: Array) => Array); + xorBy( + iteratee: ValueOnlyIteratee, + a1: Array + ): (a2: Array) => Array; + xorBy( + iteratee: ValueOnlyIteratee, + a1: Array, + a2: Array + ): Array; + symmetricDifferenceBy( + iteratee: ValueOnlyIteratee + ): ((a1: Array) => (a2: Array) => Array) & + ((a1: Array, a2: Array) => Array); + symmetricDifferenceBy( + iteratee: ValueOnlyIteratee, + a1: Array + ): (a2: Array) => Array; + symmetricDifferenceBy( + iteratee: ValueOnlyIteratee, + a1: Array, + a2: Array + ): Array; + xorWith( + comparator: Comparator + ): ((a1: Array) => (a2: Array) => Array) & + ((a1: Array, a2: Array) => Array); + xorWith( + comparator: Comparator, + a1: Array + ): (a2: Array) => Array; + xorWith(comparator: Comparator, a1: Array, a2: Array): Array; + symmetricDifferenceWith( + comparator: Comparator + ): ((a1: Array) => (a2: Array) => Array) & + ((a1: Array, a2: Array) => Array); + symmetricDifferenceWith( + comparator: Comparator, + a1: Array + ): (a2: Array) => Array; + symmetricDifferenceWith( + comparator: Comparator, + a1: Array, + a2: Array + ): Array; + zip(a1: A[]): (a2: B[]) => Array<[A, B]>; + zip(a1: A[], a2: B[]): Array<[A, B]>; + zipAll(arrays: Array>): Array; + zipObject(props?: Array): (values?: Array) => { [key: K]: V }; + zipObject(props?: Array, values?: Array): { [key: K]: V }; + zipObj(props: Array): (values: Array) => Object; + zipObj(props: Array, values: Array): Object; + zipObjectDeep(props: any[]): (values: any) => Object; + zipObjectDeep(props: any[], values: any): Object; + zipWith( + iteratee: Iteratee + ): ((a1: NestedArray) => (a2: NestedArray) => Array) & + ((a1: NestedArray, a2: NestedArray) => Array); + zipWith( + iteratee: Iteratee, + a1: NestedArray + ): (a2: NestedArray) => Array; + zipWith( + iteratee: Iteratee, + a1: NestedArray, + a2: NestedArray + ): Array; + // Collection + countBy( + iteratee: ValueOnlyIteratee + ): (collection: Array | { [id: any]: T }) => { [string]: number }; + countBy( + iteratee: ValueOnlyIteratee, + collection: Array | { [id: any]: T } + ): { [string]: number }; + // alias of _.forEach + each( + iteratee: Iteratee | OIteratee + ): (collection: $ReadOnlyArray | { [id: any]: T }) => Array; + each( + iteratee: Iteratee | OIteratee, + collection: $ReadOnlyArray | { [id: any]: T } + ): Array; + // alias of _.forEachRight + eachRight( + iteratee: Iteratee | OIteratee + ): (collection: $ReadOnlyArray | { [id: any]: T }) => Array; + eachRight( + iteratee: Iteratee | OIteratee, + collection: $ReadOnlyArray | { [id: any]: T } + ): Array; + every( + iteratee: Iteratee | OIteratee + ): (collection: $ReadOnlyArray | { [id: any]: T }) => boolean; + every( + iteratee: Iteratee | OIteratee, + collection: $ReadOnlyArray | { [id: any]: T } + ): boolean; + all( + iteratee: Iteratee | OIteratee + ): (collection: Array | { [id: any]: T }) => boolean; + all( + iteratee: Iteratee | OIteratee, + collection: Array | { [id: any]: T } + ): boolean; + filter( + predicate: Predicate | OPredicate + ): (collection: $ReadOnlyArray | { [id: any]: T }) => Array; + filter( + predicate: Predicate | OPredicate, + collection: $ReadOnlyArray | { [id: any]: T } + ): Array; + find( + predicate: Predicate | OPredicate + ): (collection: $ReadOnlyArray | { [id: any]: T }) => T | void; + find( + predicate: Predicate | OPredicate, + collection: $ReadOnlyArray | { [id: any]: T } + ): T | void; + findFrom( + predicate: Predicate | OPredicate + ): (( + fromIndex: number + ) => (collection: $ReadOnlyArray | { [id: any]: T }) => T | void) & + (( + fromIndex: number, + collection: $ReadOnlyArray | { [id: any]: T } + ) => T | void); + findFrom( + predicate: Predicate | OPredicate, + fromIndex: number + ): (collection: Array | { [id: any]: T }) => T | void; + findFrom( + predicate: Predicate | OPredicate, + fromIndex: number, + collection: $ReadOnlyArray | { [id: any]: T } + ): T | void; + findLast( + predicate: Predicate | OPredicate + ): (collection: $ReadOnlyArray | { [id: any]: T }) => T | void; + findLast( + predicate: Predicate | OPredicate, + collection: $ReadOnlyArray | { [id: any]: T } + ): T | void; + findLastFrom( + predicate: Predicate | OPredicate + ): (( + fromIndex: number + ) => (collection: $ReadOnlyArray | { [id: any]: T }) => T | void) & + (( + fromIndex: number, + collection: $ReadOnlyArray | { [id: any]: T } + ) => T | void); + findLastFrom( + predicate: Predicate | OPredicate, + fromIndex: number + ): (collection: $ReadOnlyArray | { [id: any]: T }) => T | void; + findLastFrom( + predicate: Predicate | OPredicate, + fromIndex: number, + collection: $ReadOnlyArray | { [id: any]: T } + ): T | void; + flatMap( + iteratee: FlatMapIteratee | OFlatMapIteratee + ): (collection: Array | { [id: any]: T }) => Array; + flatMap( + iteratee: FlatMapIteratee | OFlatMapIteratee, + collection: Array | { [id: any]: T } + ): Array; + flatMapDeep( + iteratee: FlatMapIteratee | OFlatMapIteratee + ): (collection: Array | { [id: any]: T }) => Array; + flatMapDeep( + iteratee: FlatMapIteratee | OFlatMapIteratee, + collection: Array | { [id: any]: T } + ): Array; + flatMapDepth( + iteratee: FlatMapIteratee | OFlatMapIteratee + ): (( + depth: number + ) => (collection: Array | { [id: any]: T }) => Array) & + ((depth: number, collection: Array | { [id: any]: T }) => Array); + flatMapDepth( + iteratee: FlatMapIteratee | OFlatMapIteratee, + depth: number + ): (collection: Array | { [id: any]: T }) => Array; + flatMapDepth( + iteratee: FlatMapIteratee | OFlatMapIteratee, + depth: number, + collection: Array | { [id: any]: T } + ): Array; + forEach( + iteratee: Iteratee | OIteratee + ): (collection: $ReadOnlyArray | { [id: any]: T }) => Array; + forEach( + iteratee: Iteratee | OIteratee, + collection: $ReadOnlyArray | { [id: any]: T } + ): Array; + forEachRight( + iteratee: Iteratee | OIteratee + ): (collection: $ReadOnlyArray | { [id: any]: T }) => Array; + forEachRight( + iteratee: Iteratee | OIteratee, + collection: $ReadOnlyArray | { [id: any]: T } + ): Array; + groupBy( + iteratee: ValueOnlyIteratee + ): ( + collection: $ReadOnlyArray | { [id: any]: T } + ) => { [key: V]: Array }; + groupBy( + iteratee: ValueOnlyIteratee, + collection: $ReadOnlyArray | { [id: any]: T } + ): { [key: V]: Array }; + includes(value: T): (collection: Array | { [id: any]: T }) => boolean; + includes(value: T, collection: Array | { [id: any]: T }): boolean; + includes(value: string): (str: string) => boolean; + includes(value: string, str: string): boolean; + contains(value: string): (str: string) => boolean; + contains(value: string, str: string): boolean; + contains(value: T): (collection: Array | { [id: any]: T }) => boolean; + contains(value: T, collection: Array | { [id: any]: T }): boolean; + includesFrom( + value: string + ): ((fromIndex: number) => (str: string) => boolean) & + ((fromIndex: number, str: string) => boolean); + includesFrom(value: string, fromIndex: number): (str: string) => boolean; + includesFrom(value: string, fromIndex: number, str: string): boolean; + includesFrom( + value: T + ): ((fromIndex: number) => (collection: Array) => boolean) & + ((fromIndex: number, collection: Array) => boolean); + includesFrom( + value: T, + fromIndex: number + ): (collection: Array) => boolean; + includesFrom(value: T, fromIndex: number, collection: Array): boolean; + invokeMap( + path: ((value: T) => Array | string) | Array | string + ): (collection: Array | { [id: any]: T }) => Array; + invokeMap( + path: ((value: T) => Array | string) | Array | string, + collection: Array | { [id: any]: T } + ): Array; + invokeArgsMap( + path: ((value: T) => Array | string) | Array | string + ): (( + collection: Array | { [id: any]: T } + ) => (args: Array) => Array) & + (( + collection: Array | { [id: any]: T }, + args: Array + ) => Array); + invokeArgsMap( + path: ((value: T) => Array | string) | Array | string, + collection: Array | { [id: any]: T } + ): (args: Array) => Array; + invokeArgsMap( + path: ((value: T) => Array | string) | Array | string, + collection: Array | { [id: any]: T }, + args: Array + ): Array; + keyBy( + iteratee: ValueOnlyIteratee + ): (collection: $ReadOnlyArray | { [id: any]: T }) => { [key: V]: T }; + keyBy( + iteratee: ValueOnlyIteratee, + collection: $ReadOnlyArray | { [id: any]: T } + ): { [key: V]: T }; + indexBy( + iteratee: ValueOnlyIteratee + ): (collection: $ReadOnlyArray | { [id: any]: T }) => { [key: V]: T }; + indexBy( + iteratee: ValueOnlyIteratee, + collection: $ReadOnlyArray | { [id: any]: T } + ): { [key: V]: T }; + map( + iteratee: MapIterator | OMapIterator + ): (collection: $ReadOnlyArray | { [id: any]: T }) => Array; + map( + iteratee: MapIterator | OMapIterator, + collection: $ReadOnlyArray | { [id: any]: T } + ): Array; + map(iteratee: (char: string) => any): (str: string) => string; + map(iteratee: (char: string) => any, str: string): string; + pluck( + iteratee: MapIterator | OMapIterator + ): (collection: Array | { [id: any]: T }) => Array; + pluck( + iteratee: MapIterator | OMapIterator, + collection: Array | { [id: any]: T } + ): Array; + pluck(iteratee: (char: string) => any): (str: string) => string; + pluck(iteratee: (char: string) => any, str: string): string; + orderBy( + iteratees: $ReadOnlyArray | OIteratee<*>> | string + ): (( + orders: $ReadOnlyArray<"asc" | "desc"> | string + ) => (collection: $ReadOnlyArray | { [id: any]: T }) => Array) & + (( + orders: $ReadOnlyArray<"asc" | "desc"> | string, + collection: $ReadOnlyArray | { [id: any]: T } + ) => Array); + orderBy( + iteratees: $ReadOnlyArray | OIteratee<*>> | string, + orders: $ReadOnlyArray<"asc" | "desc"> | string + ): (collection: $ReadOnlyArray | { [id: any]: T }) => Array; + orderBy( + iteratees: $ReadOnlyArray | OIteratee<*>> | string, + orders: $ReadOnlyArray<"asc" | "desc"> | string, + collection: $ReadOnlyArray | { [id: any]: T } + ): Array; + partition( + predicate: Predicate | OPredicate + ): (collection: Array | { [id: any]: T }) => [Array, Array]; + partition( + predicate: Predicate | OPredicate, + collection: Array | { [id: any]: T } + ): [Array, Array]; + reduce( + iteratee: (accumulator: U, value: T) => U + ): ((accumulator: U) => (collection: Array | { [id: any]: T }) => U) & + ((accumulator: U, collection: Array | { [id: any]: T }) => U); + reduce( + iteratee: (accumulator: U, value: T) => U, + accumulator: U + ): (collection: Array | { [id: any]: T }) => U; + reduce( + iteratee: (accumulator: U, value: T) => U, + accumulator: U, + collection: Array | { [id: any]: T } + ): U; + reduceRight( + iteratee: (value: T, accumulator: U) => U + ): ((accumulator: U) => (collection: Array | { [id: any]: T }) => U) & + ((accumulator: U, collection: Array | { [id: any]: T }) => U); + reduceRight( + iteratee: (value: T, accumulator: U) => U, + accumulator: U + ): (collection: Array | { [id: any]: T }) => U; + reduceRight( + iteratee: (value: T, accumulator: U) => U, + accumulator: U, + collection: Array | { [id: any]: T } + ): U; + reject( + predicate: Predicate | OPredicate + ): (collection: Array | { [id: any]: T }) => Array; + reject( + predicate: Predicate | OPredicate, + collection: Array | { [id: any]: T } + ): Array; + sample(collection: Array | { [id: any]: T }): T; + sampleSize( + n: number + ): (collection: Array | { [id: any]: T }) => Array; + sampleSize(n: number, collection: Array | { [id: any]: T }): Array; + shuffle(collection: Array | { [id: any]: T }): Array; + size(collection: $ReadOnlyArray | Object | string): number; + some( + predicate: Predicate | OPredicate + ): (collection: $ReadOnlyArray | { [id: any]: T }) => boolean; + some( + predicate: Predicate | OPredicate, + collection: $ReadOnlyArray | { [id: any]: T } + ): boolean; + any( + predicate: Predicate | OPredicate + ): (collection: $ReadOnlyArray | { [id: any]: T }) => boolean; + any( + predicate: Predicate | OPredicate, + collection: $ReadOnlyArray | { [id: any]: T } + ): boolean; + sortBy( + iteratees: + | $ReadOnlyArray | OIteratee> + | Iteratee + | OIteratee + ): (collection: $ReadOnlyArray | { [id: any]: T }) => Array; + sortBy( + iteratees: + | $ReadOnlyArray | OIteratee> + | Iteratee + | OIteratee, + collection: $ReadOnlyArray | { [id: any]: T } + ): Array; + + // Date + now(): number; + + // Function + after(fn: Function): (n: number) => Function; + after(fn: Function, n: number): Function; + ary(func: Function): Function; + nAry(n: number): (func: Function) => Function; + nAry(n: number, func: Function): Function; + before(fn: Function): (n: number) => Function; + before(fn: Function, n: number): Function; + bind(func: Function): (thisArg: any) => Function; + bind(func: Function, thisArg: any): Function; + bindKey(obj: Object): (key: string) => Function; + bindKey(obj: Object, key: string): Function; + curry: Curry; + curryN(arity: number): (func: Function) => Function; + curryN(arity: number, func: Function): Function; + curryRight(func: Function): Function; + curryRightN(arity: number): (func: Function) => Function; + curryRightN(arity: number, func: Function): Function; + debounce(wait: number): (func: F) => F; + debounce(wait: number, func: F): F; + defer(func: Function): TimeoutID; + delay(wait: number): (func: Function) => TimeoutID; + delay(wait: number, func: Function): TimeoutID; + flip(func: Function): Function; + memoize(func: F): F; + negate(predicate: Function): Function; + complement(predicate: Function): Function; + once(func: Function): Function; + overArgs(func: Function): (transforms: Array) => Function; + overArgs(func: Function, transforms: Array): Function; + useWith(func: Function): (transforms: Array) => Function; + useWith(func: Function, transforms: Array): Function; + partial(func: Function): (partials: any[]) => Function; + partial(func: Function, partials: any[]): Function; + partialRight(func: Function): (partials: Array) => Function; + partialRight(func: Function, partials: Array): Function; + rearg(indexes: Array): (func: Function) => Function; + rearg(indexes: Array, func: Function): Function; + rest(func: Function): Function; + unapply(func: Function): Function; + restFrom(start: number): (func: Function) => Function; + restFrom(start: number, func: Function): Function; + spread(func: Function): Function; + apply(func: Function): Function; + spreadFrom(start: number): (func: Function) => Function; + spreadFrom(start: number, func: Function): Function; + throttle(wait: number): (func: Function) => Function; + throttle(wait: number, func: Function): Function; + unary(func: Function): Function; + wrap(wrapper: Function): (value: any) => Function; + wrap(wrapper: Function, value: any): Function; + + // Lang + castArray(value: *): any[]; + clone(value: T): T; + cloneDeep(value: T): T; + cloneDeepWith( + customizer: (value: T, key: number | string, object: T, stack: any) => U + ): (value: T) => U; + cloneDeepWith( + customizer: (value: T, key: number | string, object: T, stack: any) => U, + value: T + ): U; + cloneWith( + customizer: (value: T, key: number | string, object: T, stack: any) => U + ): (value: T) => U; + cloneWith( + customizer: (value: T, key: number | string, object: T, stack: any) => U, + value: T + ): U; + conformsTo( + predicates: T & { [key: string]: (x: any) => boolean } + ): (source: T) => boolean; + conformsTo( + predicates: T & { [key: string]: (x: any) => boolean }, + source: T + ): boolean; + where( + predicates: T & { [key: string]: (x: any) => boolean } + ): (source: T) => boolean; + where( + predicates: T & { [key: string]: (x: any) => boolean }, + source: T + ): boolean; + conforms( + predicates: T & { [key: string]: (x: any) => boolean } + ): (source: T) => boolean; + conforms( + predicates: T & { [key: string]: (x: any) => boolean }, + source: T + ): boolean; + eq(value: any): (other: any) => boolean; + eq(value: any, other: any): boolean; + identical(value: any): (other: any) => boolean; + identical(value: any, other: any): boolean; + gt(value: any): (other: any) => boolean; + gt(value: any, other: any): boolean; + gte(value: any): (other: any) => boolean; + gte(value: any, other: any): boolean; + isArguments(value: any): boolean; + isArray(value: any): boolean; + isArrayBuffer(value: any): boolean; + isArrayLike(value: any): boolean; + isArrayLikeObject(value: any): boolean; + isBoolean(value: any): boolean; + isBuffer(value: any): boolean; + isDate(value: any): boolean; + isElement(value: any): boolean; + isEmpty(value: any): boolean; + isEqual(value: any): (other: any) => boolean; + isEqual(value: any, other: any): boolean; + equals(value: any): (other: any) => boolean; + equals(value: any, other: any): boolean; + isEqualWith( + customizer: ( + objValue: any, + otherValue: any, + key: number | string, + object: T, + other: U, + stack: any + ) => boolean | void + ): ((value: T) => (other: U) => boolean) & + ((value: T, other: U) => boolean); + isEqualWith( + customizer: ( + objValue: any, + otherValue: any, + key: number | string, + object: T, + other: U, + stack: any + ) => boolean | void, + value: T + ): (other: U) => boolean; + isEqualWith( + customizer: ( + objValue: any, + otherValue: any, + key: number | string, + object: T, + other: U, + stack: any + ) => boolean | void, + value: T, + other: U + ): boolean; + isError(value: any): boolean; + isFinite(value: any): boolean; + isFunction(value: Function): true; + isFunction(value: number | string | void | null | Object): false; + isInteger(value: any): boolean; + isLength(value: any): boolean; + isMap(value: any): boolean; + isMatch(source: Object): (object: Object) => boolean; + isMatch(source: Object, object: Object): boolean; + whereEq(source: Object): (object: Object) => boolean; + whereEq(source: Object, object: Object): boolean; + isMatchWith( + customizer: ( + objValue: any, + srcValue: any, + key: number | string, + object: T, + source: U + ) => boolean | void + ): ((source: U) => (object: T) => boolean) & + ((source: U, object: T) => boolean); + isMatchWith( + customizer: ( + objValue: any, + srcValue: any, + key: number | string, + object: T, + source: U + ) => boolean | void, + source: U + ): (object: T) => boolean; + isMatchWith( + customizer: ( + objValue: any, + srcValue: any, + key: number | string, + object: T, + source: U + ) => boolean | void, + source: U, + object: T + ): boolean; + isNaN(value: any): boolean; + isNative(value: any): boolean; + isNil(value: any): boolean; + isNull(value: any): boolean; + isNumber(value: any): boolean; + isObject(value: any): boolean; + isObjectLike(value: any): boolean; + isPlainObject(value: any): boolean; + isRegExp(value: any): boolean; + isSafeInteger(value: any): boolean; + isSet(value: any): boolean; + isString(value: string): true; + isString(value: any): false; + isSymbol(value: any): boolean; + isTypedArray(value: any): boolean; + isUndefined(value: any): boolean; + isWeakMap(value: any): boolean; + isWeakSet(value: any): boolean; + lt(value: any): (other: any) => boolean; + lt(value: any, other: any): boolean; + lte(value: any): (other: any) => boolean; + lte(value: any, other: any): boolean; + toArray(value: any): Array; + toFinite(value: any): number; + toInteger(value: any): number; + toLength(value: any): number; + toNumber(value: any): number; + toPlainObject(value: any): Object; + toSafeInteger(value: any): number; + toString(value: any): string; + + // Math + add(augend: number): (addend: number) => number; + add(augend: number, addend: number): number; + ceil(number: number): number; + divide(dividend: number): (divisor: number) => number; + divide(dividend: number, divisor: number): number; + floor(number: number): number; + max(array: Array): T; + maxBy(iteratee: Iteratee): (array: Array) => T; + maxBy(iteratee: Iteratee, array: Array): T; + mean(array: Array<*>): number; + meanBy(iteratee: Iteratee): (array: Array) => number; + meanBy(iteratee: Iteratee, array: Array): number; + min(array: Array): T; + minBy(iteratee: Iteratee): (array: Array) => T; + minBy(iteratee: Iteratee, array: Array): T; + multiply(multiplier: number): (multiplicand: number) => number; + multiply(multiplier: number, multiplicand: number): number; + round(number: number): number; + subtract(minuend: number): (subtrahend: number) => number; + subtract(minuend: number, subtrahend: number): number; + sum(array: Array<*>): number; + sumBy(iteratee: Iteratee): (array: Array) => number; + sumBy(iteratee: Iteratee, array: Array): number; + + // number + clamp( + lower: number + ): ((upper: number) => (number: number) => number) & + ((upper: number, number: number) => number); + clamp(lower: number, upper: number): (number: number) => number; + clamp(lower: number, upper: number, number: number): number; + inRange( + start: number + ): ((end: number) => (number: number) => boolean) & + ((end: number, number: number) => boolean); + inRange(start: number, end: number): (number: number) => boolean; + inRange(start: number, end: number, number: number): boolean; + random(lower: number): (upper: number) => number; + random(lower: number, upper: number): number; + + // Object + assign(object: Object): (source: Object) => Object; + assign(object: Object, source: Object): Object; + assignAll(objects: Array): Object; + assignInAll(objects: Array): Object; + extendAll(objects: Array): Object; + assignIn(a: A): (b: B) => A & B; + assignIn(a: A, b: B): A & B; + assignInWith( + customizer: ( + objValue: any, + srcValue: any, + key: string, + object: T, + source: A + ) => any | void + ): ((object: T) => (s1: A) => Object) & ((object: T, s1: A) => Object); + assignInWith( + customizer: ( + objValue: any, + srcValue: any, + key: string, + object: T, + source: A + ) => any | void, + object: T + ): (s1: A) => Object; + assignInWith( + customizer: ( + objValue: any, + srcValue: any, + key: string, + object: T, + source: A + ) => any | void, + object: T, + s1: A + ): Object; + assignWith( + customizer: ( + objValue: any, + srcValue: any, + key: string, + object: T, + source: A + ) => any | void + ): ((object: T) => (s1: A) => Object) & ((object: T, s1: A) => Object); + assignWith( + customizer: ( + objValue: any, + srcValue: any, + key: string, + object: T, + source: A + ) => any | void, + object: T + ): (s1: A) => Object; + assignWith( + customizer: ( + objValue: any, + srcValue: any, + key: string, + object: T, + source: A + ) => any | void, + object: T, + s1: A + ): Object; + assignInAllWith( + customizer: ( + objValue: any, + srcValue: any, + key: string, + object: Object, + source: Object + ) => any | void + ): (objects: Array) => Object; + assignInAllWith( + customizer: ( + objValue: any, + srcValue: any, + key: string, + object: Object, + source: Object + ) => any | void, + objects: Array + ): Object; + extendAllWith( + customizer: ( + objValue: any, + srcValue: any, + key: string, + object: Object, + source: Object + ) => any | void + ): (objects: Array) => Object; + extendAllWith( + customizer: ( + objValue: any, + srcValue: any, + key: string, + object: Object, + source: Object + ) => any | void, + objects: Array + ): Object; + assignAllWith( + customizer: ( + objValue: any, + srcValue: any, + key: string, + object: Object, + source: Object + ) => any | void + ): (objects: Array) => Object; + assignAllWith( + customizer: ( + objValue: any, + srcValue: any, + key: string, + object: Object, + source: Object + ) => any | void, + objects: Array + ): Object; + at(paths: Array): (object: Object) => Array; + at(paths: Array, object: Object): Array; + props(paths: Array): (object: Object) => Array; + props(paths: Array, object: Object): Array; + paths(paths: Array): (object: Object) => Array; + paths(paths: Array, object: Object): Array; + create(prototype: T): $Supertype; + defaults(source: Object): (object: Object) => Object; + defaults(source: Object, object: Object): Object; + defaultsAll(objects: Array): Object; + defaultsDeep(source: Object): (object: Object) => Object; + defaultsDeep(source: Object, object: Object): Object; + defaultsDeepAll(objects: Array): Object; + // alias for _.toPairs + entries(object: Object): Array<[string, any]>; + // alias for _.toPairsIn + entriesIn(object: Object): Array<[string, any]>; + // alias for _.assignIn + extend(a: A): (b: B) => A & B; + extend(a: A, b: B): A & B; + // alias for _.assignInWith + extendWith( + customizer: ( + objValue: any, + srcValue: any, + key: string, + object: T, + source: A + ) => any | void + ): ((object: T) => (s1: A) => Object) & ((object: T, s1: A) => Object); + extendWith( + customizer: ( + objValue: any, + srcValue: any, + key: string, + object: T, + source: A + ) => any | void, + object: T + ): (s1: A) => Object; + extendWith( + customizer: ( + objValue: any, + srcValue: any, + key: string, + object: T, + source: A + ) => any | void, + object: T, + s1: A + ): Object; + findKey( + predicate: OPredicate + ): (object: T) => string | void; + findKey( + predicate: OPredicate, + object: T + ): string | void; + findLastKey( + predicate: OPredicate + ): (object: T) => string | void; + findLastKey( + predicate: OPredicate, + object: T + ): string | void; + forIn(iteratee: OIteratee<*>): (object: Object) => Object; + forIn(iteratee: OIteratee<*>, object: Object): Object; + forInRight(iteratee: OIteratee<*>): (object: Object) => Object; + forInRight(iteratee: OIteratee<*>, object: Object): Object; + forOwn(iteratee: OIteratee<*>): (object: Object) => Object; + forOwn(iteratee: OIteratee<*>, object: Object): Object; + forOwnRight(iteratee: OIteratee<*>): (object: Object) => Object; + forOwnRight(iteratee: OIteratee<*>, object: Object): Object; + functions(object: Object): Array; + functionsIn(object: Object): Array; + get( + path: $ReadOnlyArray | string | number + ): (object: Object | $ReadOnlyArray | void | null) => any; + get( + path: $ReadOnlyArray | string | number, + object: Object | $ReadOnlyArray | void | null + ): any; + prop(path: Array | string): (object: Object | Array) => any; + prop(path: Array | string, object: Object | Array): any; + path(path: Array | string): (object: Object | Array) => any; + path(path: Array | string, object: Object | Array): any; + getOr( + defaultValue: any + ): (( + path: Array | string + ) => (object: Object | Array) => any) & + (( + path: Array | string, + object: Object | $ReadOnlyArray | void | null + ) => any); + getOr( + defaultValue: any, + path: Array | string + ): (object: Object | $ReadOnlyArray | void | null) => any; + getOr( + defaultValue: any, + path: Array | string, + object: Object | $ReadOnlyArray | void | null + ): any; + propOr( + defaultValue: any + ): (( + path: Array | string + ) => (object: Object | Array) => any) & + ((path: Array | string, object: Object | Array) => any); + propOr( + defaultValue: any, + path: Array | string + ): (object: Object | Array) => any; + propOr( + defaultValue: any, + path: Array | string, + object: Object | Array + ): any; + pathOr( + defaultValue: any + ): (( + path: Array | string + ) => (object: Object | Array) => any) & + ((path: Array | string, object: Object | Array) => any); + pathOr( + defaultValue: any, + path: Array | string + ): (object: Object | Array) => any; + pathOr( + defaultValue: any, + path: Array | string, + object: Object | Array + ): any; + has(path: Array | string): (object: Object) => boolean; + has(path: Array | string, object: Object): boolean; + hasIn(path: Array | string): (object: Object) => boolean; + hasIn(path: Array | string, object: Object): boolean; + invert(object: Object): Object; + invertObj(object: Object): Object; + invertBy(iteratee: Function): (object: Object) => Object; + invertBy(iteratee: Function, object: Object): Object; + invoke(path: Array | string): (object: Object) => any; + invoke(path: Array | string, object: Object): any; + invokeArgs( + path: Array | string + ): ((object: Object) => (args: Array) => any) & + ((object: Object, args: Array) => any); + invokeArgs( + path: Array | string, + object: Object + ): (args: Array) => any; + invokeArgs( + path: Array | string, + object: Object, + args: Array + ): any; + keys(object: { [key: K]: any }): Array; + keys(object: Object): Array; + keysIn(object: Object): Array; + mapKeys(iteratee: OIteratee<*>): (object: Object) => Object; + mapKeys(iteratee: OIteratee<*>, object: Object): Object; + mapValues(iteratee: OIteratee<*>): (object: Object) => Object; + mapValues(iteratee: OIteratee<*>, object: Object): Object; + merge(object: Object): (source: Object) => Object; + merge(object: Object, source: Object): Object; + mergeAll(objects: Array): Object; + mergeWith( + customizer: ( + objValue: any, + srcValue: any, + key: string, + object: T, + source: A | B + ) => any | void + ): ((object: T) => (s1: A) => Object) & ((object: T, s1: A) => Object); + mergeWith( + customizer: ( + objValue: any, + srcValue: any, + key: string, + object: T, + source: A | B + ) => any | void, + object: T + ): (s1: A) => Object; + mergeWith( + customizer: ( + objValue: any, + srcValue: any, + key: string, + object: T, + source: A | B + ) => any | void, + object: T, + s1: A + ): Object; + mergeAllWith( + customizer: ( + objValue: any, + srcValue: any, + key: string, + object: Object, + source: Object + ) => any | void + ): (objects: Array) => Object; + mergeAllWith( + customizer: ( + objValue: any, + srcValue: any, + key: string, + object: Object, + source: Object + ) => any | void, + objects: Array + ): Object; + omit(props: Array): (object: Object) => Object; + omit(props: Array, object: Object): Object; + omitAll(props: Array): (object: Object) => Object; + omitAll(props: Array, object: Object): Object; + omitBy( + predicate: OPredicate + ): (object: T) => Object; + omitBy(predicate: OPredicate, object: T): Object; + pick(props: Array): (object: Object) => Object; + pick(props: Array, object: Object): Object; + pickAll(props: Array): (object: Object) => Object; + pickAll(props: Array, object: Object): Object; + pickBy( + predicate: OPredicate + ): (object: T) => Object; + pickBy(predicate: OPredicate, object: T): Object; + result(path: Array | string): (object: Object) => any; + result(path: Array | string, object: Object): any; + set( + path: Array | string + ): ((value: any) => (object: Object) => Object) & + ((value: any, object: Object) => Object); + set(path: Array | string, value: any): (object: Object) => Object; + set(path: Array | string, value: any, object: Object): Object; + assoc( + path: Array | string + ): ((value: any) => (object: Object) => Object) & + ((value: any, object: Object) => Object); + assoc(path: Array | string, value: any): (object: Object) => Object; + assoc(path: Array | string, value: any, object: Object): Object; + assocPath( + path: Array | string + ): ((value: any) => (object: Object) => Object) & + ((value: any, object: Object) => Object); + assocPath( + path: Array | string, + value: any + ): (object: Object) => Object; + assocPath(path: Array | string, value: any, object: Object): Object; + setWith( + customizer: (nsValue: any, key: string, nsObject: T) => any + ): (( + path: Array | string + ) => ((value: any) => (object: T) => Object) & + ((value: any, object: T) => Object)) & + ((path: Array | string, value: any) => (object: T) => Object) & + ((path: Array | string, value: any, object: T) => Object); + setWith( + customizer: (nsValue: any, key: string, nsObject: T) => any, + path: Array | string + ): ((value: any) => (object: T) => Object) & + ((value: any, object: T) => Object); + setWith( + customizer: (nsValue: any, key: string, nsObject: T) => any, + path: Array | string, + value: any + ): (object: T) => Object; + setWith( + customizer: (nsValue: any, key: string, nsObject: T) => any, + path: Array | string, + value: any, + object: T + ): Object; + toPairs(object: Object | Array<*>): Array<[string, any]>; + toPairsIn(object: Object): Array<[string, any]>; + transform( + iteratee: OIteratee<*> + ): (( + accumulator: any + ) => (collection: Object | $ReadOnlyArray) => any) & + ((accumulator: any, collection: Object | $ReadOnlyArray) => any); + transform( + iteratee: OIteratee<*>, + accumulator: any + ): (collection: Object | $ReadOnlyArray) => any; + transform( + iteratee: OIteratee<*>, + accumulator: any, + collection: Object | $ReadOnlyArray + ): any; + unset(path: Array | string): (object: Object) => Object; + unset(path: Array | string, object: Object): Object; + dissoc(path: Array | string): (object: Object) => Object; + dissoc(path: Array | string, object: Object): Object; + dissocPath(path: Array | string): (object: Object) => Object; + dissocPath(path: Array | string, object: Object): Object; + update( + path: string[] | string + ): ((updater: Function) => (object: Object) => Object) & + ((updater: Function, object: Object) => Object); + update( + path: string[] | string, + updater: Function + ): (object: Object) => Object; + update(path: string[] | string, updater: Function, object: Object): Object; + updateWith( + customizer: Function + ): (( + path: string[] | string + ) => ((updater: Function) => (object: Object) => Object) & + ((updater: Function, object: Object) => Object)) & + (( + path: string[] | string, + updater: Function + ) => (object: Object) => Object) & + ((path: string[] | string, updater: Function, object: Object) => Object); + updateWith( + customizer: Function, + path: string[] | string + ): ((updater: Function) => (object: Object) => Object) & + ((updater: Function, object: Object) => Object); + updateWith( + customizer: Function, + path: string[] | string, + updater: Function + ): (object: Object) => Object; + updateWith( + customizer: Function, + path: string[] | string, + updater: Function, + object: Object + ): Object; + values(object: Object): Array; + valuesIn(object: Object): Array; + + tap(interceptor: (value: T) => any): (value: T) => T; + tap(interceptor: (value: T) => any, value: T): T; + thru(interceptor: (value: T1) => T2): (value: T1) => T2; + thru(interceptor: (value: T1) => T2, value: T1): T2; + + // String + camelCase(string: string): string; + capitalize(string: string): string; + deburr(string: string): string; + endsWith(target: string): (string: string) => boolean; + endsWith(target: string, string: string): boolean; + escape(string: string): string; + escapeRegExp(string: string): string; + kebabCase(string: string): string; + lowerCase(string: string): string; + lowerFirst(string: string): string; + pad(length: number): (string: string) => string; + pad(length: number, string: string): string; + padChars( + chars: string + ): ((length: number) => (string: string) => string) & + ((length: number, string: string) => string); + padChars(chars: string, length: number): (string: string) => string; + padChars(chars: string, length: number, string: string): string; + padEnd(length: number): (string: string) => string; + padEnd(length: number, string: string): string; + padCharsEnd( + chars: string + ): ((length: number) => (string: string) => string) & + ((length: number, string: string) => string); + padCharsEnd(chars: string, length: number): (string: string) => string; + padCharsEnd(chars: string, length: number, string: string): string; + padStart(length: number): (string: string) => string; + padStart(length: number, string: string): string; + padCharsStart( + chars: string + ): ((length: number) => (string: string) => string) & + ((length: number, string: string) => string); + padCharsStart(chars: string, length: number): (string: string) => string; + padCharsStart(chars: string, length: number, string: string): string; + parseInt(radix: number): (string: string) => number; + parseInt(radix: number, string: string): number; + repeat(n: number): (string: string) => string; + repeat(n: number, string: string): string; + replace( + pattern: RegExp | string + ): (( + replacement: ((string: string) => string) | string + ) => (string: string) => string) & + (( + replacement: ((string: string) => string) | string, + string: string + ) => string); + replace( + pattern: RegExp | string, + replacement: ((string: string) => string) | string + ): (string: string) => string; + replace( + pattern: RegExp | string, + replacement: ((string: string) => string) | string, + string: string + ): string; + snakeCase(string: string): string; + split(separator: RegExp | string): (string: string) => Array; + split(separator: RegExp | string, string: string): Array; + startCase(string: string): string; + startsWith(target: string): (string: string) => boolean; + startsWith(target: string, string: string): boolean; + template(string: string): Function; + toLower(string: string): string; + toUpper(string: string): string; + trim(string: string): string; + trimChars(chars: string): (string: string) => string; + trimChars(chars: string, string: string): string; + trimEnd(string: string): string; + trimCharsEnd(chars: string): (string: string) => string; + trimCharsEnd(chars: string, string: string): string; + trimStart(string: string): string; + trimCharsStart(chars: string): (string: string) => string; + trimCharsStart(chars: string, string: string): string; + truncate(options: TruncateOptions): (string: string) => string; + truncate(options: TruncateOptions, string: string): string; + unescape(string: string): string; + upperCase(string: string): string; + upperFirst(string: string): string; + words(string: string): Array; + + // Util + attempt(func: Function): any; + bindAll(methodNames: Array): (object: Object) => Object; + bindAll(methodNames: Array, object: Object): Object; + cond(pairs: NestedArray): Function; + constant(value: T): () => T; + always(value: T): () => T; + defaultTo( + defaultValue: T2 + ): (value: T1) => T1; + defaultTo( + defaultValue: T2, + value: T1 + ): T1; + // NaN is a number instead of its own type, otherwise it would behave like null/void + defaultTo(defaultValue: T2): (value: T1) => T1 | T2; + defaultTo(defaultValue: T2, value: T1): T1 | T2; + defaultTo(defaultValue: T2): (value: T1) => T2; + defaultTo(defaultValue: T2, value: T1): T2; + flow: $ComposeReverse & ((funcs: Array) => Function); + pipe: $ComposeReverse & ((funcs: Array) => Function); + flowRight: $Compose & ((funcs: Array) => Function); + compose: $Compose & ((funcs: Array) => Function); + compose(funcs: Array): Function; + identity(value: T): T; + iteratee(func: any): Function; + matches(source: Object): (object: Object) => boolean; + matches(source: Object, object: Object): boolean; + matchesProperty(path: Array | string): (srcValue: any) => Function; + matchesProperty(path: Array | string, srcValue: any): Function; + propEq(path: Array | string): (srcValue: any) => Function; + propEq(path: Array | string, srcValue: any): Function; + pathEq(path: Array | string): (srcValue: any) => Function; + pathEq(path: Array | string, srcValue: any): Function; + method(path: Array | string): Function; + methodOf(object: Object): Function; + mixin( + object: T + ): ((source: Object) => (options: { chain: boolean }) => T) & + ((source: Object, options: { chain: boolean }) => T); + mixin( + object: T, + source: Object + ): (options: { chain: boolean }) => T; + mixin( + object: T, + source: Object, + options: { chain: boolean } + ): T; + noConflict(): Lodash; + noop(...args: Array): void; + nthArg(n: number): Function; + over(iteratees: Array): Function; + juxt(iteratees: Array): Function; + overEvery(predicates: Array): Function; + allPass(predicates: Array): Function; + overSome(predicates: Array): Function; + anyPass(predicates: Array): Function; + property( + path: Array | string + ): (object: Object | Array) => any; + property(path: Array | string, object: Object | Array): any; + propertyOf(object: Object): (path: Array | string) => Function; + propertyOf(object: Object, path: Array | string): Function; + range(start: number): (end: number) => Array; + range(start: number, end: number): Array; + rangeStep( + step: number + ): ((start: number) => (end: number) => Array) & + ((start: number, end: number) => Array); + rangeStep(step: number, start: number): (end: number) => Array; + rangeStep(step: number, start: number, end: number): Array; + rangeRight(start: number): (end: number) => Array; + rangeRight(start: number, end: number): Array; + rangeStepRight( + step: number + ): ((start: number) => (end: number) => Array) & + ((start: number, end: number) => Array); + rangeStepRight(step: number, start: number): (end: number) => Array; + rangeStepRight(step: number, start: number, end: number): Array; + runInContext(context: Object): Function; + + stubArray(): Array<*>; + stubFalse(): false; + F(): false; + stubObject(): {}; + stubString(): ""; + stubTrue(): true; + T(): true; + times(iteratee: (i: number) => T): (n: number) => Array; + times(iteratee: (i: number) => T, n: number): Array; + toPath(value: any): Array; + uniqueId(prefix: string): string; + + __: any; + placeholder: any; + + convert(options: { + cap?: boolean, + curry?: boolean, + fixed?: boolean, + immutable?: boolean, + rearg?: boolean + }): void; + + // Properties + VERSION: string; + templateSettings: TemplateSettings; + } + + declare module.exports: Lodash; +} + +declare module "lodash/chunk" { + declare module.exports: $PropertyType<$Exports<"lodash">, "chunk">; +} + +declare module "lodash/compact" { + declare module.exports: $PropertyType<$Exports<"lodash">, "compact">; +} + +declare module "lodash/concat" { + declare module.exports: $PropertyType<$Exports<"lodash">, "concat">; +} + +declare module "lodash/difference" { + declare module.exports: $PropertyType<$Exports<"lodash">, "difference">; +} + +declare module "lodash/differenceBy" { + declare module.exports: $PropertyType<$Exports<"lodash">, "differenceBy">; +} + +declare module "lodash/differenceWith" { + declare module.exports: $PropertyType<$Exports<"lodash">, "differenceWith">; +} + +declare module "lodash/drop" { + declare module.exports: $PropertyType<$Exports<"lodash">, "drop">; +} + +declare module "lodash/dropRight" { + declare module.exports: $PropertyType<$Exports<"lodash">, "dropRight">; +} + +declare module "lodash/dropRightWhile" { + declare module.exports: $PropertyType<$Exports<"lodash">, "dropRightWhile">; +} + +declare module "lodash/dropWhile" { + declare module.exports: $PropertyType<$Exports<"lodash">, "dropWhile">; +} + +declare module "lodash/fill" { + declare module.exports: $PropertyType<$Exports<"lodash">, "fill">; +} + +declare module "lodash/findIndex" { + declare module.exports: $PropertyType<$Exports<"lodash">, "findIndex">; +} + +declare module "lodash/findLastIndex" { + declare module.exports: $PropertyType<$Exports<"lodash">, "findLastIndex">; +} + +declare module "lodash/first" { + declare module.exports: $PropertyType<$Exports<"lodash">, "first">; +} + +declare module "lodash/flatten" { + declare module.exports: $PropertyType<$Exports<"lodash">, "flatten">; +} + +declare module "lodash/flattenDeep" { + declare module.exports: $PropertyType<$Exports<"lodash">, "flattenDeep">; +} + +declare module "lodash/flattenDepth" { + declare module.exports: $PropertyType<$Exports<"lodash">, "flattenDepth">; +} + +declare module "lodash/fromPairs" { + declare module.exports: $PropertyType<$Exports<"lodash">, "fromPairs">; +} + +declare module "lodash/head" { + declare module.exports: $PropertyType<$Exports<"lodash">, "head">; +} + +declare module "lodash/indexOf" { + declare module.exports: $PropertyType<$Exports<"lodash">, "indexOf">; +} + +declare module "lodash/initial" { + declare module.exports: $PropertyType<$Exports<"lodash">, "initial">; +} + +declare module "lodash/intersection" { + declare module.exports: $PropertyType<$Exports<"lodash">, "intersection">; +} + +declare module "lodash/intersectionBy" { + declare module.exports: $PropertyType<$Exports<"lodash">, "intersectionBy">; +} + +declare module "lodash/intersectionWith" { + declare module.exports: $PropertyType<$Exports<"lodash">, "intersectionWith">; +} + +declare module "lodash/join" { + declare module.exports: $PropertyType<$Exports<"lodash">, "join">; +} + +declare module "lodash/last" { + declare module.exports: $PropertyType<$Exports<"lodash">, "last">; +} + +declare module "lodash/lastIndexOf" { + declare module.exports: $PropertyType<$Exports<"lodash">, "lastIndexOf">; +} + +declare module "lodash/nth" { + declare module.exports: $PropertyType<$Exports<"lodash">, "nth">; +} + +declare module "lodash/pull" { + declare module.exports: $PropertyType<$Exports<"lodash">, "pull">; +} + +declare module "lodash/pullAll" { + declare module.exports: $PropertyType<$Exports<"lodash">, "pullAll">; +} + +declare module "lodash/pullAllBy" { + declare module.exports: $PropertyType<$Exports<"lodash">, "pullAllBy">; +} + +declare module "lodash/pullAllWith" { + declare module.exports: $PropertyType<$Exports<"lodash">, "pullAllWith">; +} + +declare module "lodash/pullAt" { + declare module.exports: $PropertyType<$Exports<"lodash">, "pullAt">; +} + +declare module "lodash/remove" { + declare module.exports: $PropertyType<$Exports<"lodash">, "remove">; +} + +declare module "lodash/reverse" { + declare module.exports: $PropertyType<$Exports<"lodash">, "reverse">; +} + +declare module "lodash/slice" { + declare module.exports: $PropertyType<$Exports<"lodash">, "slice">; +} + +declare module "lodash/sortedIndex" { + declare module.exports: $PropertyType<$Exports<"lodash">, "sortedIndex">; +} + +declare module "lodash/sortedIndexBy" { + declare module.exports: $PropertyType<$Exports<"lodash">, "sortedIndexBy">; +} + +declare module "lodash/sortedIndexOf" { + declare module.exports: $PropertyType<$Exports<"lodash">, "sortedIndexOf">; +} + +declare module "lodash/sortedLastIndex" { + declare module.exports: $PropertyType<$Exports<"lodash">, "sortedLastIndex">; +} + +declare module "lodash/sortedLastIndexBy" { + declare module.exports: $PropertyType< + $Exports<"lodash">, + "sortedLastIndexBy" + >; +} + +declare module "lodash/sortedLastIndexOf" { + declare module.exports: $PropertyType< + $Exports<"lodash">, + "sortedLastIndexOf" + >; +} + +declare module "lodash/sortedUniq" { + declare module.exports: $PropertyType<$Exports<"lodash">, "sortedUniq">; +} + +declare module "lodash/sortedUniqBy" { + declare module.exports: $PropertyType<$Exports<"lodash">, "sortedUniqBy">; +} + +declare module "lodash/tail" { + declare module.exports: $PropertyType<$Exports<"lodash">, "tail">; +} + +declare module "lodash/take" { + declare module.exports: $PropertyType<$Exports<"lodash">, "take">; +} + +declare module "lodash/takeRight" { + declare module.exports: $PropertyType<$Exports<"lodash">, "takeRight">; +} + +declare module "lodash/takeRightWhile" { + declare module.exports: $PropertyType<$Exports<"lodash">, "takeRightWhile">; +} + +declare module "lodash/takeWhile" { + declare module.exports: $PropertyType<$Exports<"lodash">, "takeWhile">; +} + +declare module "lodash/union" { + declare module.exports: $PropertyType<$Exports<"lodash">, "union">; +} + +declare module "lodash/unionBy" { + declare module.exports: $PropertyType<$Exports<"lodash">, "unionBy">; +} + +declare module "lodash/unionWith" { + declare module.exports: $PropertyType<$Exports<"lodash">, "unionWith">; +} + +declare module "lodash/uniq" { + declare module.exports: $PropertyType<$Exports<"lodash">, "uniq">; +} + +declare module "lodash/uniqBy" { + declare module.exports: $PropertyType<$Exports<"lodash">, "uniqBy">; +} + +declare module "lodash/uniqWith" { + declare module.exports: $PropertyType<$Exports<"lodash">, "uniqWith">; +} + +declare module "lodash/unzip" { + declare module.exports: $PropertyType<$Exports<"lodash">, "unzip">; +} + +declare module "lodash/unzipWith" { + declare module.exports: $PropertyType<$Exports<"lodash">, "unzipWith">; +} + +declare module "lodash/without" { + declare module.exports: $PropertyType<$Exports<"lodash">, "without">; +} + +declare module "lodash/xor" { + declare module.exports: $PropertyType<$Exports<"lodash">, "xor">; +} + +declare module "lodash/xorBy" { + declare module.exports: $PropertyType<$Exports<"lodash">, "xorBy">; +} + +declare module "lodash/xorWith" { + declare module.exports: $PropertyType<$Exports<"lodash">, "xorWith">; +} + +declare module "lodash/zip" { + declare module.exports: $PropertyType<$Exports<"lodash">, "zip">; +} + +declare module "lodash/zipObject" { + declare module.exports: $PropertyType<$Exports<"lodash">, "zipObject">; +} + +declare module "lodash/zipObjectDeep" { + declare module.exports: $PropertyType<$Exports<"lodash">, "zipObjectDeep">; +} + +declare module "lodash/zipWith" { + declare module.exports: $PropertyType<$Exports<"lodash">, "zipWith">; +} + +declare module "lodash/countBy" { + declare module.exports: $PropertyType<$Exports<"lodash">, "countBy">; +} + +declare module "lodash/each" { + declare module.exports: $PropertyType<$Exports<"lodash">, "each">; +} + +declare module "lodash/eachRight" { + declare module.exports: $PropertyType<$Exports<"lodash">, "eachRight">; +} + +declare module "lodash/every" { + declare module.exports: $PropertyType<$Exports<"lodash">, "every">; +} + +declare module "lodash/filter" { + declare module.exports: $PropertyType<$Exports<"lodash">, "filter">; +} + +declare module "lodash/find" { + declare module.exports: $PropertyType<$Exports<"lodash">, "find">; +} + +declare module "lodash/findLast" { + declare module.exports: $PropertyType<$Exports<"lodash">, "findLast">; +} + +declare module "lodash/flatMap" { + declare module.exports: $PropertyType<$Exports<"lodash">, "flatMap">; +} + +declare module "lodash/flatMapDeep" { + declare module.exports: $PropertyType<$Exports<"lodash">, "flatMapDeep">; +} + +declare module "lodash/flatMapDepth" { + declare module.exports: $PropertyType<$Exports<"lodash">, "flatMapDepth">; +} + +declare module "lodash/forEach" { + declare module.exports: $PropertyType<$Exports<"lodash">, "forEach">; +} + +declare module "lodash/forEachRight" { + declare module.exports: $PropertyType<$Exports<"lodash">, "forEachRight">; +} + +declare module "lodash/groupBy" { + declare module.exports: $PropertyType<$Exports<"lodash">, "groupBy">; +} + +declare module "lodash/includes" { + declare module.exports: $PropertyType<$Exports<"lodash">, "includes">; +} + +declare module "lodash/invokeMap" { + declare module.exports: $PropertyType<$Exports<"lodash">, "invokeMap">; +} + +declare module "lodash/keyBy" { + declare module.exports: $PropertyType<$Exports<"lodash">, "keyBy">; +} + +declare module "lodash/map" { + declare module.exports: $PropertyType<$Exports<"lodash">, "map">; +} + +declare module "lodash/orderBy" { + declare module.exports: $PropertyType<$Exports<"lodash">, "orderBy">; +} + +declare module "lodash/partition" { + declare module.exports: $PropertyType<$Exports<"lodash">, "partition">; +} + +declare module "lodash/reduce" { + declare module.exports: $PropertyType<$Exports<"lodash">, "reduce">; +} + +declare module "lodash/reduceRight" { + declare module.exports: $PropertyType<$Exports<"lodash">, "reduceRight">; +} + +declare module "lodash/reject" { + declare module.exports: $PropertyType<$Exports<"lodash">, "reject">; +} + +declare module "lodash/sample" { + declare module.exports: $PropertyType<$Exports<"lodash">, "sample">; +} + +declare module "lodash/sampleSize" { + declare module.exports: $PropertyType<$Exports<"lodash">, "sampleSize">; +} + +declare module "lodash/shuffle" { + declare module.exports: $PropertyType<$Exports<"lodash">, "shuffle">; +} + +declare module "lodash/size" { + declare module.exports: $PropertyType<$Exports<"lodash">, "size">; +} + +declare module "lodash/some" { + declare module.exports: $PropertyType<$Exports<"lodash">, "some">; +} + +declare module "lodash/sortBy" { + declare module.exports: $PropertyType<$Exports<"lodash">, "sortBy">; +} + +declare module "lodash/now" { + declare module.exports: $PropertyType<$Exports<"lodash">, "now">; +} + +declare module "lodash/after" { + declare module.exports: $PropertyType<$Exports<"lodash">, "after">; +} + +declare module "lodash/ary" { + declare module.exports: $PropertyType<$Exports<"lodash">, "ary">; +} + +declare module "lodash/before" { + declare module.exports: $PropertyType<$Exports<"lodash">, "before">; +} + +declare module "lodash/bind" { + declare module.exports: $PropertyType<$Exports<"lodash">, "bind">; +} + +declare module "lodash/bindKey" { + declare module.exports: $PropertyType<$Exports<"lodash">, "bindKey">; +} + +declare module "lodash/curry" { + declare module.exports: $PropertyType<$Exports<"lodash">, "curry">; +} + +declare module "lodash/curryRight" { + declare module.exports: $PropertyType<$Exports<"lodash">, "curryRight">; +} + +declare module "lodash/debounce" { + declare module.exports: $PropertyType<$Exports<"lodash">, "debounce">; +} + +declare module "lodash/defer" { + declare module.exports: $PropertyType<$Exports<"lodash">, "defer">; +} + +declare module "lodash/delay" { + declare module.exports: $PropertyType<$Exports<"lodash">, "delay">; +} + +declare module "lodash/flip" { + declare module.exports: $PropertyType<$Exports<"lodash">, "flip">; +} + +declare module "lodash/memoize" { + declare module.exports: $PropertyType<$Exports<"lodash">, "memoize">; +} + +declare module "lodash/negate" { + declare module.exports: $PropertyType<$Exports<"lodash">, "negate">; +} + +declare module "lodash/once" { + declare module.exports: $PropertyType<$Exports<"lodash">, "once">; +} + +declare module "lodash/overArgs" { + declare module.exports: $PropertyType<$Exports<"lodash">, "overArgs">; +} + +declare module "lodash/partial" { + declare module.exports: $PropertyType<$Exports<"lodash">, "partial">; +} + +declare module "lodash/partialRight" { + declare module.exports: $PropertyType<$Exports<"lodash">, "partialRight">; +} + +declare module "lodash/rearg" { + declare module.exports: $PropertyType<$Exports<"lodash">, "rearg">; +} + +declare module "lodash/rest" { + declare module.exports: $PropertyType<$Exports<"lodash">, "rest">; +} + +declare module "lodash/spread" { + declare module.exports: $PropertyType<$Exports<"lodash">, "spread">; +} + +declare module "lodash/throttle" { + declare module.exports: $PropertyType<$Exports<"lodash">, "throttle">; +} + +declare module "lodash/unary" { + declare module.exports: $PropertyType<$Exports<"lodash">, "unary">; +} + +declare module "lodash/wrap" { + declare module.exports: $PropertyType<$Exports<"lodash">, "wrap">; +} + +declare module "lodash/castArray" { + declare module.exports: $PropertyType<$Exports<"lodash">, "castArray">; +} + +declare module "lodash/clone" { + declare module.exports: $PropertyType<$Exports<"lodash">, "clone">; +} + +declare module "lodash/cloneDeep" { + declare module.exports: $PropertyType<$Exports<"lodash">, "cloneDeep">; +} + +declare module "lodash/cloneDeepWith" { + declare module.exports: $PropertyType<$Exports<"lodash">, "cloneDeepWith">; +} + +declare module "lodash/cloneWith" { + declare module.exports: $PropertyType<$Exports<"lodash">, "cloneWith">; +} + +declare module "lodash/conformsTo" { + declare module.exports: $PropertyType<$Exports<"lodash">, "conformsTo">; +} + +declare module "lodash/eq" { + declare module.exports: $PropertyType<$Exports<"lodash">, "eq">; +} + +declare module "lodash/gt" { + declare module.exports: $PropertyType<$Exports<"lodash">, "gt">; +} + +declare module "lodash/gte" { + declare module.exports: $PropertyType<$Exports<"lodash">, "gte">; +} + +declare module "lodash/isArguments" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isArguments">; +} + +declare module "lodash/isArray" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isArray">; +} + +declare module "lodash/isArrayBuffer" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isArrayBuffer">; +} + +declare module "lodash/isArrayLike" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isArrayLike">; +} + +declare module "lodash/isArrayLikeObject" { + declare module.exports: $PropertyType< + $Exports<"lodash">, + "isArrayLikeObject" + >; +} + +declare module "lodash/isBoolean" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isBoolean">; +} + +declare module "lodash/isBuffer" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isBuffer">; +} + +declare module "lodash/isDate" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isDate">; +} + +declare module "lodash/isElement" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isElement">; +} + +declare module "lodash/isEmpty" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isEmpty">; +} + +declare module "lodash/isEqual" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isEqual">; +} + +declare module "lodash/isEqualWith" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isEqualWith">; +} + +declare module "lodash/isError" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isError">; +} + +declare module "lodash/isFinite" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isFinite">; +} + +declare module "lodash/isFunction" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isFunction">; +} + +declare module "lodash/isInteger" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isInteger">; +} + +declare module "lodash/isLength" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isLength">; +} + +declare module "lodash/isMap" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isMap">; +} + +declare module "lodash/isMatch" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isMatch">; +} + +declare module "lodash/isMatchWith" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isMatchWith">; +} + +declare module "lodash/isNaN" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isNaN">; +} + +declare module "lodash/isNative" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isNative">; +} + +declare module "lodash/isNil" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isNil">; +} + +declare module "lodash/isNull" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isNull">; +} + +declare module "lodash/isNumber" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isNumber">; +} + +declare module "lodash/isObject" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isObject">; +} + +declare module "lodash/isObjectLike" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isObjectLike">; +} + +declare module "lodash/isPlainObject" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isPlainObject">; +} + +declare module "lodash/isRegExp" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isRegExp">; +} + +declare module "lodash/isSafeInteger" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isSafeInteger">; +} + +declare module "lodash/isSet" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isSet">; +} + +declare module "lodash/isString" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isString">; +} + +declare module "lodash/isSymbol" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isSymbol">; +} + +declare module "lodash/isTypedArray" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isTypedArray">; +} + +declare module "lodash/isUndefined" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isUndefined">; +} + +declare module "lodash/isWeakMap" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isWeakMap">; +} + +declare module "lodash/isWeakSet" { + declare module.exports: $PropertyType<$Exports<"lodash">, "isWeakSet">; +} + +declare module "lodash/lt" { + declare module.exports: $PropertyType<$Exports<"lodash">, "lt">; +} + +declare module "lodash/lte" { + declare module.exports: $PropertyType<$Exports<"lodash">, "lte">; +} + +declare module "lodash/toArray" { + declare module.exports: $PropertyType<$Exports<"lodash">, "toArray">; +} + +declare module "lodash/toFinite" { + declare module.exports: $PropertyType<$Exports<"lodash">, "toFinite">; +} + +declare module "lodash/toInteger" { + declare module.exports: $PropertyType<$Exports<"lodash">, "toInteger">; +} + +declare module "lodash/toLength" { + declare module.exports: $PropertyType<$Exports<"lodash">, "toLength">; +} + +declare module "lodash/toNumber" { + declare module.exports: $PropertyType<$Exports<"lodash">, "toNumber">; +} + +declare module "lodash/toPlainObject" { + declare module.exports: $PropertyType<$Exports<"lodash">, "toPlainObject">; +} + +declare module "lodash/toSafeInteger" { + declare module.exports: $PropertyType<$Exports<"lodash">, "toSafeInteger">; +} + +declare module "lodash/toString" { + declare module.exports: $PropertyType<$Exports<"lodash">, "toString">; +} + +declare module "lodash/add" { + declare module.exports: $PropertyType<$Exports<"lodash">, "add">; +} + +declare module "lodash/ceil" { + declare module.exports: $PropertyType<$Exports<"lodash">, "ceil">; +} + +declare module "lodash/divide" { + declare module.exports: $PropertyType<$Exports<"lodash">, "divide">; +} + +declare module "lodash/floor" { + declare module.exports: $PropertyType<$Exports<"lodash">, "floor">; +} + +declare module "lodash/max" { + declare module.exports: $PropertyType<$Exports<"lodash">, "max">; +} + +declare module "lodash/maxBy" { + declare module.exports: $PropertyType<$Exports<"lodash">, "maxBy">; +} + +declare module "lodash/mean" { + declare module.exports: $PropertyType<$Exports<"lodash">, "mean">; +} + +declare module "lodash/meanBy" { + declare module.exports: $PropertyType<$Exports<"lodash">, "meanBy">; +} + +declare module "lodash/min" { + declare module.exports: $PropertyType<$Exports<"lodash">, "min">; +} + +declare module "lodash/minBy" { + declare module.exports: $PropertyType<$Exports<"lodash">, "minBy">; +} + +declare module "lodash/multiply" { + declare module.exports: $PropertyType<$Exports<"lodash">, "multiply">; +} + +declare module "lodash/round" { + declare module.exports: $PropertyType<$Exports<"lodash">, "round">; +} + +declare module "lodash/subtract" { + declare module.exports: $PropertyType<$Exports<"lodash">, "subtract">; +} + +declare module "lodash/sum" { + declare module.exports: $PropertyType<$Exports<"lodash">, "sum">; +} + +declare module "lodash/sumBy" { + declare module.exports: $PropertyType<$Exports<"lodash">, "sumBy">; +} + +declare module "lodash/clamp" { + declare module.exports: $PropertyType<$Exports<"lodash">, "clamp">; +} + +declare module "lodash/inRange" { + declare module.exports: $PropertyType<$Exports<"lodash">, "inRange">; +} + +declare module "lodash/random" { + declare module.exports: $PropertyType<$Exports<"lodash">, "random">; +} + +declare module "lodash/assign" { + declare module.exports: $PropertyType<$Exports<"lodash">, "assign">; +} + +declare module "lodash/assignIn" { + declare module.exports: $PropertyType<$Exports<"lodash">, "assignIn">; +} + +declare module "lodash/assignInWith" { + declare module.exports: $PropertyType<$Exports<"lodash">, "assignInWith">; +} + +declare module "lodash/assignWith" { + declare module.exports: $PropertyType<$Exports<"lodash">, "assignWith">; +} + +declare module "lodash/at" { + declare module.exports: $PropertyType<$Exports<"lodash">, "at">; +} + +declare module "lodash/create" { + declare module.exports: $PropertyType<$Exports<"lodash">, "create">; +} + +declare module "lodash/defaults" { + declare module.exports: $PropertyType<$Exports<"lodash">, "defaults">; +} + +declare module "lodash/defaultsDeep" { + declare module.exports: $PropertyType<$Exports<"lodash">, "defaultsDeep">; +} + +declare module "lodash/entries" { + declare module.exports: $PropertyType<$Exports<"lodash">, "entries">; +} + +declare module "lodash/entriesIn" { + declare module.exports: $PropertyType<$Exports<"lodash">, "entriesIn">; +} + +declare module "lodash/extend" { + declare module.exports: $PropertyType<$Exports<"lodash">, "extend">; +} + +declare module "lodash/extendWith" { + declare module.exports: $PropertyType<$Exports<"lodash">, "extendWith">; +} + +declare module "lodash/findKey" { + declare module.exports: $PropertyType<$Exports<"lodash">, "findKey">; +} + +declare module "lodash/findLastKey" { + declare module.exports: $PropertyType<$Exports<"lodash">, "findLastKey">; +} + +declare module "lodash/forIn" { + declare module.exports: $PropertyType<$Exports<"lodash">, "forIn">; +} + +declare module "lodash/forInRight" { + declare module.exports: $PropertyType<$Exports<"lodash">, "forInRight">; +} + +declare module "lodash/forOwn" { + declare module.exports: $PropertyType<$Exports<"lodash">, "forOwn">; +} + +declare module "lodash/forOwnRight" { + declare module.exports: $PropertyType<$Exports<"lodash">, "forOwnRight">; +} + +declare module "lodash/functions" { + declare module.exports: $PropertyType<$Exports<"lodash">, "functions">; +} + +declare module "lodash/functionsIn" { + declare module.exports: $PropertyType<$Exports<"lodash">, "functionsIn">; +} + +declare module "lodash/get" { + declare module.exports: $PropertyType<$Exports<"lodash">, "get">; +} + +declare module "lodash/has" { + declare module.exports: $PropertyType<$Exports<"lodash">, "has">; +} + +declare module "lodash/hasIn" { + declare module.exports: $PropertyType<$Exports<"lodash">, "hasIn">; +} + +declare module "lodash/invert" { + declare module.exports: $PropertyType<$Exports<"lodash">, "invert">; +} + +declare module "lodash/invertBy" { + declare module.exports: $PropertyType<$Exports<"lodash">, "invertBy">; +} + +declare module "lodash/invoke" { + declare module.exports: $PropertyType<$Exports<"lodash">, "invoke">; +} + +declare module "lodash/keys" { + declare module.exports: $PropertyType<$Exports<"lodash">, "keys">; +} + +declare module "lodash/keysIn" { + declare module.exports: $PropertyType<$Exports<"lodash">, "keysIn">; +} + +declare module "lodash/mapKeys" { + declare module.exports: $PropertyType<$Exports<"lodash">, "mapKeys">; +} + +declare module "lodash/mapValues" { + declare module.exports: $PropertyType<$Exports<"lodash">, "mapValues">; +} + +declare module "lodash/merge" { + declare module.exports: $PropertyType<$Exports<"lodash">, "merge">; +} + +declare module "lodash/mergeWith" { + declare module.exports: $PropertyType<$Exports<"lodash">, "mergeWith">; +} + +declare module "lodash/omit" { + declare module.exports: $PropertyType<$Exports<"lodash">, "omit">; +} + +declare module "lodash/omitBy" { + declare module.exports: $PropertyType<$Exports<"lodash">, "omitBy">; +} + +declare module "lodash/pick" { + declare module.exports: $PropertyType<$Exports<"lodash">, "pick">; +} + +declare module "lodash/pickBy" { + declare module.exports: $PropertyType<$Exports<"lodash">, "pickBy">; +} + +declare module "lodash/result" { + declare module.exports: $PropertyType<$Exports<"lodash">, "result">; +} + +declare module "lodash/set" { + declare module.exports: $PropertyType<$Exports<"lodash">, "set">; +} + +declare module "lodash/setWith" { + declare module.exports: $PropertyType<$Exports<"lodash">, "setWith">; +} + +declare module "lodash/toPairs" { + declare module.exports: $PropertyType<$Exports<"lodash">, "toPairs">; +} + +declare module "lodash/toPairsIn" { + declare module.exports: $PropertyType<$Exports<"lodash">, "toPairsIn">; +} + +declare module "lodash/transform" { + declare module.exports: $PropertyType<$Exports<"lodash">, "transform">; +} + +declare module "lodash/unset" { + declare module.exports: $PropertyType<$Exports<"lodash">, "unset">; +} + +declare module "lodash/update" { + declare module.exports: $PropertyType<$Exports<"lodash">, "update">; +} + +declare module "lodash/updateWith" { + declare module.exports: $PropertyType<$Exports<"lodash">, "updateWith">; +} + +declare module "lodash/values" { + declare module.exports: $PropertyType<$Exports<"lodash">, "values">; +} + +declare module "lodash/valuesIn" { + declare module.exports: $PropertyType<$Exports<"lodash">, "valuesIn">; +} + +declare module "lodash/chain" { + declare module.exports: $PropertyType<$Exports<"lodash">, "chain">; +} + +declare module "lodash/tap" { + declare module.exports: $PropertyType<$Exports<"lodash">, "tap">; +} + +declare module "lodash/thru" { + declare module.exports: $PropertyType<$Exports<"lodash">, "thru">; +} + +declare module "lodash/camelCase" { + declare module.exports: $PropertyType<$Exports<"lodash">, "camelCase">; +} + +declare module "lodash/capitalize" { + declare module.exports: $PropertyType<$Exports<"lodash">, "capitalize">; +} + +declare module "lodash/deburr" { + declare module.exports: $PropertyType<$Exports<"lodash">, "deburr">; +} + +declare module "lodash/endsWith" { + declare module.exports: $PropertyType<$Exports<"lodash">, "endsWith">; +} + +declare module "lodash/escape" { + declare module.exports: $PropertyType<$Exports<"lodash">, "escape">; +} + +declare module "lodash/escapeRegExp" { + declare module.exports: $PropertyType<$Exports<"lodash">, "escapeRegExp">; +} + +declare module "lodash/kebabCase" { + declare module.exports: $PropertyType<$Exports<"lodash">, "kebabCase">; +} + +declare module "lodash/lowerCase" { + declare module.exports: $PropertyType<$Exports<"lodash">, "lowerCase">; +} + +declare module "lodash/lowerFirst" { + declare module.exports: $PropertyType<$Exports<"lodash">, "lowerFirst">; +} + +declare module "lodash/pad" { + declare module.exports: $PropertyType<$Exports<"lodash">, "pad">; +} + +declare module "lodash/padEnd" { + declare module.exports: $PropertyType<$Exports<"lodash">, "padEnd">; +} + +declare module "lodash/padStart" { + declare module.exports: $PropertyType<$Exports<"lodash">, "padStart">; +} + +declare module "lodash/parseInt" { + declare module.exports: $PropertyType<$Exports<"lodash">, "parseInt">; +} + +declare module "lodash/repeat" { + declare module.exports: $PropertyType<$Exports<"lodash">, "repeat">; +} + +declare module "lodash/replace" { + declare module.exports: $PropertyType<$Exports<"lodash">, "replace">; +} + +declare module "lodash/snakeCase" { + declare module.exports: $PropertyType<$Exports<"lodash">, "snakeCase">; +} + +declare module "lodash/split" { + declare module.exports: $PropertyType<$Exports<"lodash">, "split">; +} + +declare module "lodash/startCase" { + declare module.exports: $PropertyType<$Exports<"lodash">, "startCase">; +} + +declare module "lodash/startsWith" { + declare module.exports: $PropertyType<$Exports<"lodash">, "startsWith">; +} + +declare module "lodash/template" { + declare module.exports: $PropertyType<$Exports<"lodash">, "template">; +} + +declare module "lodash/toLower" { + declare module.exports: $PropertyType<$Exports<"lodash">, "toLower">; +} + +declare module "lodash/toUpper" { + declare module.exports: $PropertyType<$Exports<"lodash">, "toUpper">; +} + +declare module "lodash/trim" { + declare module.exports: $PropertyType<$Exports<"lodash">, "trim">; +} + +declare module "lodash/trimEnd" { + declare module.exports: $PropertyType<$Exports<"lodash">, "trimEnd">; +} + +declare module "lodash/trimStart" { + declare module.exports: $PropertyType<$Exports<"lodash">, "trimStart">; +} + +declare module "lodash/truncate" { + declare module.exports: $PropertyType<$Exports<"lodash">, "truncate">; +} + +declare module "lodash/unescape" { + declare module.exports: $PropertyType<$Exports<"lodash">, "unescape">; +} + +declare module "lodash/upperCase" { + declare module.exports: $PropertyType<$Exports<"lodash">, "upperCase">; +} + +declare module "lodash/upperFirst" { + declare module.exports: $PropertyType<$Exports<"lodash">, "upperFirst">; +} + +declare module "lodash/words" { + declare module.exports: $PropertyType<$Exports<"lodash">, "words">; +} + +declare module "lodash/attempt" { + declare module.exports: $PropertyType<$Exports<"lodash">, "attempt">; +} + +declare module "lodash/bindAll" { + declare module.exports: $PropertyType<$Exports<"lodash">, "bindAll">; +} + +declare module "lodash/cond" { + declare module.exports: $PropertyType<$Exports<"lodash">, "cond">; +} + +declare module "lodash/conforms" { + declare module.exports: $PropertyType<$Exports<"lodash">, "conforms">; +} + +declare module "lodash/constant" { + declare module.exports: $PropertyType<$Exports<"lodash">, "constant">; +} + +declare module "lodash/defaultTo" { + declare module.exports: $PropertyType<$Exports<"lodash">, "defaultTo">; +} + +declare module "lodash/flow" { + declare module.exports: $PropertyType<$Exports<"lodash">, "flow">; +} + +declare module "lodash/flowRight" { + declare module.exports: $PropertyType<$Exports<"lodash">, "flowRight">; +} + +declare module "lodash/identity" { + declare module.exports: $PropertyType<$Exports<"lodash">, "identity">; +} + +declare module "lodash/iteratee" { + declare module.exports: $PropertyType<$Exports<"lodash">, "iteratee">; +} + +declare module "lodash/matches" { + declare module.exports: $PropertyType<$Exports<"lodash">, "matches">; +} + +declare module "lodash/matchesProperty" { + declare module.exports: $PropertyType<$Exports<"lodash">, "matchesProperty">; +} + +declare module "lodash/method" { + declare module.exports: $PropertyType<$Exports<"lodash">, "method">; +} + +declare module "lodash/methodOf" { + declare module.exports: $PropertyType<$Exports<"lodash">, "methodOf">; +} + +declare module "lodash/mixin" { + declare module.exports: $PropertyType<$Exports<"lodash">, "mixin">; +} + +declare module "lodash/noConflict" { + declare module.exports: $PropertyType<$Exports<"lodash">, "noConflict">; +} + +declare module "lodash/noop" { + declare module.exports: $PropertyType<$Exports<"lodash">, "noop">; +} + +declare module "lodash/nthArg" { + declare module.exports: $PropertyType<$Exports<"lodash">, "nthArg">; +} + +declare module "lodash/over" { + declare module.exports: $PropertyType<$Exports<"lodash">, "over">; +} + +declare module "lodash/overEvery" { + declare module.exports: $PropertyType<$Exports<"lodash">, "overEvery">; +} + +declare module "lodash/overSome" { + declare module.exports: $PropertyType<$Exports<"lodash">, "overSome">; +} + +declare module "lodash/property" { + declare module.exports: $PropertyType<$Exports<"lodash">, "property">; +} + +declare module "lodash/propertyOf" { + declare module.exports: $PropertyType<$Exports<"lodash">, "propertyOf">; +} + +declare module "lodash/range" { + declare module.exports: $PropertyType<$Exports<"lodash">, "range">; +} + +declare module "lodash/rangeRight" { + declare module.exports: $PropertyType<$Exports<"lodash">, "rangeRight">; +} + +declare module "lodash/runInContext" { + declare module.exports: $PropertyType<$Exports<"lodash">, "runInContext">; +} + +declare module "lodash/stubArray" { + declare module.exports: $PropertyType<$Exports<"lodash">, "stubArray">; +} + +declare module "lodash/stubFalse" { + declare module.exports: $PropertyType<$Exports<"lodash">, "stubFalse">; +} + +declare module "lodash/stubObject" { + declare module.exports: $PropertyType<$Exports<"lodash">, "stubObject">; +} + +declare module "lodash/stubString" { + declare module.exports: $PropertyType<$Exports<"lodash">, "stubString">; +} + +declare module "lodash/stubTrue" { + declare module.exports: $PropertyType<$Exports<"lodash">, "stubTrue">; +} + +declare module "lodash/times" { + declare module.exports: $PropertyType<$Exports<"lodash">, "times">; +} + +declare module "lodash/toPath" { + declare module.exports: $PropertyType<$Exports<"lodash">, "toPath">; +} + +declare module "lodash/uniqueId" { + declare module.exports: $PropertyType<$Exports<"lodash">, "uniqueId">; +} + +declare module "lodash/fp/chunk" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "chunk">; +} + +declare module "lodash/fp/compact" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "compact">; +} + +declare module "lodash/fp/concat" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "concat">; +} + +declare module "lodash/fp/difference" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "difference">; +} + +declare module "lodash/fp/differenceBy" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "differenceBy">; +} + +declare module "lodash/fp/differenceWith" { + declare module.exports: $PropertyType< + $Exports<"lodash/fp">, + "differenceWith" + >; +} + +declare module "lodash/fp/drop" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "drop">; +} + +declare module "lodash/fp/dropLast" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "dropLast">; +} + +declare module "lodash/fp/dropRight" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "dropRight">; +} + +declare module "lodash/fp/dropRightWhile" { + declare module.exports: $PropertyType< + $Exports<"lodash/fp">, + "dropRightWhile" + >; +} + +declare module "lodash/fp/dropWhile" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "dropWhile">; +} + +declare module "lodash/fp/dropLastWhile" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "dropLastWhile">; +} + +declare module "lodash/fp/fill" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "fill">; +} + +declare module "lodash/fp/findIndex" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "findIndex">; +} + +declare module "lodash/fp/findIndexFrom" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "findIndexFrom">; +} + +declare module "lodash/fp/findLastIndex" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "findLastIndex">; +} + +declare module "lodash/fp/findLastIndexFrom" { + declare module.exports: $PropertyType< + $Exports<"lodash/fp">, + "findLastIndexFrom" + >; +} + +declare module "lodash/fp/first" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "first">; +} + +declare module "lodash/fp/flatten" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "flatten">; +} + +declare module "lodash/fp/unnest" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "unnest">; +} + +declare module "lodash/fp/flattenDeep" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "flattenDeep">; +} + +declare module "lodash/fp/flattenDepth" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "flattenDepth">; +} + +declare module "lodash/fp/fromPairs" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "fromPairs">; +} + +declare module "lodash/fp/head" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "head">; +} + +declare module "lodash/fp/indexOf" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "indexOf">; +} + +declare module "lodash/fp/indexOfFrom" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "indexOfFrom">; +} + +declare module "lodash/fp/initial" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "initial">; +} + +declare module "lodash/fp/init" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "init">; +} + +declare module "lodash/fp/intersection" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "intersection">; +} + +declare module "lodash/fp/intersectionBy" { + declare module.exports: $PropertyType< + $Exports<"lodash/fp">, + "intersectionBy" + >; +} + +declare module "lodash/fp/intersectionWith" { + declare module.exports: $PropertyType< + $Exports<"lodash/fp">, + "intersectionWith" + >; +} + +declare module "lodash/fp/join" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "join">; +} + +declare module "lodash/fp/last" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "last">; +} + +declare module "lodash/fp/lastIndexOf" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "lastIndexOf">; +} + +declare module "lodash/fp/lastIndexOfFrom" { + declare module.exports: $PropertyType< + $Exports<"lodash/fp">, + "lastIndexOfFrom" + >; +} + +declare module "lodash/fp/nth" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "nth">; +} + +declare module "lodash/fp/pull" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "pull">; +} + +declare module "lodash/fp/pullAll" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "pullAll">; +} + +declare module "lodash/fp/pullAllBy" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "pullAllBy">; +} + +declare module "lodash/fp/pullAllWith" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "pullAllWith">; +} + +declare module "lodash/fp/pullAt" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "pullAt">; +} + +declare module "lodash/fp/remove" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "remove">; +} + +declare module "lodash/fp/reverse" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "reverse">; +} + +declare module "lodash/fp/slice" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "slice">; +} + +declare module "lodash/fp/sortedIndex" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "sortedIndex">; +} + +declare module "lodash/fp/sortedIndexBy" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "sortedIndexBy">; +} + +declare module "lodash/fp/sortedIndexOf" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "sortedIndexOf">; +} + +declare module "lodash/fp/sortedLastIndex" { + declare module.exports: $PropertyType< + $Exports<"lodash/fp">, + "sortedLastIndex" + >; +} + +declare module "lodash/fp/sortedLastIndexBy" { + declare module.exports: $PropertyType< + $Exports<"lodash/fp">, + "sortedLastIndexBy" + >; +} + +declare module "lodash/fp/sortedLastIndexOf" { + declare module.exports: $PropertyType< + $Exports<"lodash/fp">, + "sortedLastIndexOf" + >; +} + +declare module "lodash/fp/sortedUniq" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "sortedUniq">; +} + +declare module "lodash/fp/sortedUniqBy" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "sortedUniqBy">; +} + +declare module "lodash/fp/tail" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "tail">; +} + +declare module "lodash/fp/take" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "take">; +} + +declare module "lodash/fp/takeRight" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "takeRight">; +} + +declare module "lodash/fp/takeLast" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "takeLast">; +} + +declare module "lodash/fp/takeRightWhile" { + declare module.exports: $PropertyType< + $Exports<"lodash/fp">, + "takeRightWhile" + >; +} + +declare module "lodash/fp/takeLastWhile" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "takeLastWhile">; +} + +declare module "lodash/fp/takeWhile" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "takeWhile">; +} + +declare module "lodash/fp/union" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "union">; +} + +declare module "lodash/fp/unionBy" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "unionBy">; +} + +declare module "lodash/fp/unionWith" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "unionWith">; +} + +declare module "lodash/fp/uniq" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "uniq">; +} + +declare module "lodash/fp/uniqBy" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "uniqBy">; +} + +declare module "lodash/fp/uniqWith" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "uniqWith">; +} + +declare module "lodash/fp/unzip" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "unzip">; +} + +declare module "lodash/fp/unzipWith" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "unzipWith">; +} + +declare module "lodash/fp/without" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "without">; +} + +declare module "lodash/fp/xor" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "xor">; +} + +declare module "lodash/fp/symmetricDifference" { + declare module.exports: $PropertyType< + $Exports<"lodash/fp">, + "symmetricDifference" + >; +} + +declare module "lodash/fp/xorBy" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "xorBy">; +} + +declare module "lodash/fp/symmetricDifferenceBy" { + declare module.exports: $PropertyType< + $Exports<"lodash/fp">, + "symmetricDifferenceBy" + >; +} + +declare module "lodash/fp/xorWith" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "xorWith">; +} + +declare module "lodash/fp/symmetricDifferenceWith" { + declare module.exports: $PropertyType< + $Exports<"lodash/fp">, + "symmetricDifferenceWith" + >; +} + +declare module "lodash/fp/zip" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "zip">; +} + +declare module "lodash/fp/zipAll" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "zipAll">; +} + +declare module "lodash/fp/zipObject" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "zipObject">; +} + +declare module "lodash/fp/zipObj" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "zipObj">; +} + +declare module "lodash/fp/zipObjectDeep" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "zipObjectDeep">; +} + +declare module "lodash/fp/zipWith" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "zipWith">; +} + +declare module "lodash/fp/countBy" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "countBy">; +} + +declare module "lodash/fp/each" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "each">; +} + +declare module "lodash/fp/eachRight" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "eachRight">; +} + +declare module "lodash/fp/every" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "every">; +} + +declare module "lodash/fp/all" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "all">; +} + +declare module "lodash/fp/filter" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "filter">; +} + +declare module "lodash/fp/find" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "find">; +} + +declare module "lodash/fp/findFrom" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "findFrom">; +} + +declare module "lodash/fp/findLast" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "findLast">; +} + +declare module "lodash/fp/findLastFrom" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "findLastFrom">; +} + +declare module "lodash/fp/flatMap" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "flatMap">; +} + +declare module "lodash/fp/flatMapDeep" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "flatMapDeep">; +} + +declare module "lodash/fp/flatMapDepth" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "flatMapDepth">; +} + +declare module "lodash/fp/forEach" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "forEach">; +} + +declare module "lodash/fp/forEachRight" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "forEachRight">; +} + +declare module "lodash/fp/groupBy" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "groupBy">; +} + +declare module "lodash/fp/includes" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "includes">; +} + +declare module "lodash/fp/contains" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "contains">; +} + +declare module "lodash/fp/includesFrom" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "includesFrom">; +} + +declare module "lodash/fp/invokeMap" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "invokeMap">; +} + +declare module "lodash/fp/invokeArgsMap" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "invokeArgsMap">; +} + +declare module "lodash/fp/keyBy" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "keyBy">; +} + +declare module "lodash/fp/indexBy" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "indexBy">; +} + +declare module "lodash/fp/map" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "map">; +} + +declare module "lodash/fp/pluck" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "pluck">; +} + +declare module "lodash/fp/orderBy" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "orderBy">; +} + +declare module "lodash/fp/partition" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "partition">; +} + +declare module "lodash/fp/reduce" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "reduce">; +} + +declare module "lodash/fp/reduceRight" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "reduceRight">; +} + +declare module "lodash/fp/reject" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "reject">; +} + +declare module "lodash/fp/sample" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "sample">; +} + +declare module "lodash/fp/sampleSize" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "sampleSize">; +} + +declare module "lodash/fp/shuffle" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "shuffle">; +} + +declare module "lodash/fp/size" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "size">; +} + +declare module "lodash/fp/some" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "some">; +} + +declare module "lodash/fp/any" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "any">; +} + +declare module "lodash/fp/sortBy" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "sortBy">; +} + +declare module "lodash/fp/now" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "now">; +} + +declare module "lodash/fp/after" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "after">; +} + +declare module "lodash/fp/ary" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "ary">; +} + +declare module "lodash/fp/nAry" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "nAry">; +} + +declare module "lodash/fp/before" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "before">; +} + +declare module "lodash/fp/bind" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "bind">; +} + +declare module "lodash/fp/bindKey" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "bindKey">; +} + +declare module "lodash/fp/curry" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "curry">; +} + +declare module "lodash/fp/curryN" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "curryN">; +} + +declare module "lodash/fp/curryRight" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "curryRight">; +} + +declare module "lodash/fp/curryRightN" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "curryRightN">; +} + +declare module "lodash/fp/debounce" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "debounce">; +} + +declare module "lodash/fp/defer" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "defer">; +} + +declare module "lodash/fp/delay" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "delay">; +} + +declare module "lodash/fp/flip" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "flip">; +} + +declare module "lodash/fp/memoize" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "memoize">; +} + +declare module "lodash/fp/negate" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "negate">; +} + +declare module "lodash/fp/complement" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "complement">; +} + +declare module "lodash/fp/once" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "once">; +} + +declare module "lodash/fp/overArgs" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "overArgs">; +} + +declare module "lodash/fp/useWith" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "useWith">; +} + +declare module "lodash/fp/partial" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "partial">; +} + +declare module "lodash/fp/partialRight" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "partialRight">; +} + +declare module "lodash/fp/rearg" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "rearg">; +} + +declare module "lodash/fp/rest" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "rest">; +} + +declare module "lodash/fp/unapply" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "unapply">; +} + +declare module "lodash/fp/restFrom" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "restFrom">; +} + +declare module "lodash/fp/spread" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "spread">; +} + +declare module "lodash/fp/apply" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "apply">; +} + +declare module "lodash/fp/spreadFrom" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "spreadFrom">; +} + +declare module "lodash/fp/throttle" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "throttle">; +} + +declare module "lodash/fp/unary" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "unary">; +} + +declare module "lodash/fp/wrap" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "wrap">; +} + +declare module "lodash/fp/castArray" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "castArray">; +} + +declare module "lodash/fp/clone" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "clone">; +} + +declare module "lodash/fp/cloneDeep" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "cloneDeep">; +} + +declare module "lodash/fp/cloneDeepWith" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "cloneDeepWith">; +} + +declare module "lodash/fp/cloneWith" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "cloneWith">; +} + +declare module "lodash/fp/conformsTo" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "conformsTo">; +} + +declare module "lodash/fp/where" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "where">; +} + +declare module "lodash/fp/conforms" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "conforms">; +} + +declare module "lodash/fp/eq" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "eq">; +} + +declare module "lodash/fp/identical" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "identical">; +} + +declare module "lodash/fp/gt" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "gt">; +} + +declare module "lodash/fp/gte" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "gte">; +} + +declare module "lodash/fp/isArguments" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isArguments">; +} + +declare module "lodash/fp/isArray" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isArray">; +} + +declare module "lodash/fp/isArrayBuffer" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isArrayBuffer">; +} + +declare module "lodash/fp/isArrayLike" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isArrayLike">; +} + +declare module "lodash/fp/isArrayLikeObject" { + declare module.exports: $PropertyType< + $Exports<"lodash/fp">, + "isArrayLikeObject" + >; +} + +declare module "lodash/fp/isBoolean" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isBoolean">; +} + +declare module "lodash/fp/isBuffer" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isBuffer">; +} + +declare module "lodash/fp/isDate" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isDate">; +} + +declare module "lodash/fp/isElement" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isElement">; +} + +declare module "lodash/fp/isEmpty" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isEmpty">; +} + +declare module "lodash/fp/isEqual" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isEqual">; +} + +declare module "lodash/fp/equals" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "equals">; +} + +declare module "lodash/fp/isEqualWith" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isEqualWith">; +} + +declare module "lodash/fp/isError" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isError">; +} + +declare module "lodash/fp/isFinite" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isFinite">; +} + +declare module "lodash/fp/isFunction" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isFunction">; +} + +declare module "lodash/fp/isInteger" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isInteger">; +} + +declare module "lodash/fp/isLength" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isLength">; +} + +declare module "lodash/fp/isMap" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isMap">; +} + +declare module "lodash/fp/isMatch" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isMatch">; +} + +declare module "lodash/fp/whereEq" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "whereEq">; +} + +declare module "lodash/fp/isMatchWith" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isMatchWith">; +} + +declare module "lodash/fp/isNaN" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isNaN">; +} + +declare module "lodash/fp/isNative" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isNative">; +} + +declare module "lodash/fp/isNil" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isNil">; +} + +declare module "lodash/fp/isNull" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isNull">; +} + +declare module "lodash/fp/isNumber" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isNumber">; +} + +declare module "lodash/fp/isObject" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isObject">; +} + +declare module "lodash/fp/isObjectLike" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isObjectLike">; +} + +declare module "lodash/fp/isPlainObject" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isPlainObject">; +} + +declare module "lodash/fp/isRegExp" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isRegExp">; +} + +declare module "lodash/fp/isSafeInteger" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isSafeInteger">; +} + +declare module "lodash/fp/isSet" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isSet">; +} + +declare module "lodash/fp/isString" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isString">; +} + +declare module "lodash/fp/isSymbol" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isSymbol">; +} + +declare module "lodash/fp/isTypedArray" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isTypedArray">; +} + +declare module "lodash/fp/isUndefined" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isUndefined">; +} + +declare module "lodash/fp/isWeakMap" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isWeakMap">; +} + +declare module "lodash/fp/isWeakSet" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "isWeakSet">; +} + +declare module "lodash/fp/lt" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "lt">; +} + +declare module "lodash/fp/lte" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "lte">; +} + +declare module "lodash/fp/toArray" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "toArray">; +} + +declare module "lodash/fp/toFinite" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "toFinite">; +} + +declare module "lodash/fp/toInteger" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "toInteger">; +} + +declare module "lodash/fp/toLength" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "toLength">; +} + +declare module "lodash/fp/toNumber" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "toNumber">; +} + +declare module "lodash/fp/toPlainObject" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "toPlainObject">; +} + +declare module "lodash/fp/toSafeInteger" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "toSafeInteger">; +} + +declare module "lodash/fp/toString" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "toString">; +} + +declare module "lodash/fp/add" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "add">; +} + +declare module "lodash/fp/ceil" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "ceil">; +} + +declare module "lodash/fp/divide" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "divide">; +} + +declare module "lodash/fp/floor" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "floor">; +} + +declare module "lodash/fp/max" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "max">; +} + +declare module "lodash/fp/maxBy" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "maxBy">; +} + +declare module "lodash/fp/mean" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "mean">; +} + +declare module "lodash/fp/meanBy" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "meanBy">; +} + +declare module "lodash/fp/min" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "min">; +} + +declare module "lodash/fp/minBy" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "minBy">; +} + +declare module "lodash/fp/multiply" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "multiply">; +} + +declare module "lodash/fp/round" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "round">; +} + +declare module "lodash/fp/subtract" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "subtract">; +} + +declare module "lodash/fp/sum" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "sum">; +} + +declare module "lodash/fp/sumBy" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "sumBy">; +} + +declare module "lodash/fp/clamp" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "clamp">; +} + +declare module "lodash/fp/inRange" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "inRange">; +} + +declare module "lodash/fp/random" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "random">; +} + +declare module "lodash/fp/assign" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "assign">; +} + +declare module "lodash/fp/assignAll" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "assignAll">; +} + +declare module "lodash/fp/assignInAll" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "assignInAll">; +} + +declare module "lodash/fp/extendAll" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "extendAll">; +} + +declare module "lodash/fp/assignIn" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "assignIn">; +} + +declare module "lodash/fp/assignInWith" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "assignInWith">; +} + +declare module "lodash/fp/assignWith" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "assignWith">; +} + +declare module "lodash/fp/assignInAllWith" { + declare module.exports: $PropertyType< + $Exports<"lodash/fp">, + "assignInAllWith" + >; +} + +declare module "lodash/fp/extendAllWith" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "extendAllWith">; +} + +declare module "lodash/fp/assignAllWith" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "assignAllWith">; +} + +declare module "lodash/fp/at" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "at">; +} + +declare module "lodash/fp/props" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "props">; +} + +declare module "lodash/fp/paths" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "paths">; +} + +declare module "lodash/fp/create" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "create">; +} + +declare module "lodash/fp/defaults" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "defaults">; +} + +declare module "lodash/fp/defaultsAll" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "defaultsAll">; +} + +declare module "lodash/fp/defaultsDeep" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "defaultsDeep">; +} + +declare module "lodash/fp/defaultsDeepAll" { + declare module.exports: $PropertyType< + $Exports<"lodash/fp">, + "defaultsDeepAll" + >; +} + +declare module "lodash/fp/entries" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "entries">; +} + +declare module "lodash/fp/entriesIn" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "entriesIn">; +} + +declare module "lodash/fp/extend" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "extend">; +} + +declare module "lodash/fp/extendWith" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "extendWith">; +} + +declare module "lodash/fp/findKey" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "findKey">; +} + +declare module "lodash/fp/findLastKey" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "findLastKey">; +} + +declare module "lodash/fp/forIn" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "forIn">; +} + +declare module "lodash/fp/forInRight" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "forInRight">; +} + +declare module "lodash/fp/forOwn" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "forOwn">; +} + +declare module "lodash/fp/forOwnRight" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "forOwnRight">; +} + +declare module "lodash/fp/functions" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "functions">; +} + +declare module "lodash/fp/functionsIn" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "functionsIn">; +} + +declare module "lodash/fp/get" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "get">; +} + +declare module "lodash/fp/prop" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "prop">; +} + +declare module "lodash/fp/path" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "path">; +} + +declare module "lodash/fp/getOr" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "getOr">; +} + +declare module "lodash/fp/propOr" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "propOr">; +} + +declare module "lodash/fp/pathOr" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "pathOr">; +} + +declare module "lodash/fp/has" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "has">; +} + +declare module "lodash/fp/hasIn" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "hasIn">; +} + +declare module "lodash/fp/invert" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "invert">; +} + +declare module "lodash/fp/invertObj" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "invertObj">; +} + +declare module "lodash/fp/invertBy" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "invertBy">; +} + +declare module "lodash/fp/invoke" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "invoke">; +} + +declare module "lodash/fp/invokeArgs" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "invokeArgs">; +} + +declare module "lodash/fp/keys" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "keys">; +} + +declare module "lodash/fp/keysIn" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "keysIn">; +} + +declare module "lodash/fp/mapKeys" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "mapKeys">; +} + +declare module "lodash/fp/mapValues" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "mapValues">; +} + +declare module "lodash/fp/merge" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "merge">; +} + +declare module "lodash/fp/mergeAll" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "mergeAll">; +} + +declare module "lodash/fp/mergeWith" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "mergeWith">; +} + +declare module "lodash/fp/mergeAllWith" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "mergeAllWith">; +} + +declare module "lodash/fp/omit" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "omit">; +} + +declare module "lodash/fp/omitAll" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "omitAll">; +} + +declare module "lodash/fp/omitBy" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "omitBy">; +} + +declare module "lodash/fp/pick" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "pick">; +} + +declare module "lodash/fp/pickAll" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "pickAll">; +} + +declare module "lodash/fp/pickBy" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "pickBy">; +} + +declare module "lodash/fp/result" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "result">; +} + +declare module "lodash/fp/set" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "set">; +} + +declare module "lodash/fp/assoc" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "assoc">; +} + +declare module "lodash/fp/assocPath" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "assocPath">; +} + +declare module "lodash/fp/setWith" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "setWith">; +} + +declare module "lodash/fp/toPairs" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "toPairs">; +} + +declare module "lodash/fp/toPairsIn" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "toPairsIn">; +} + +declare module "lodash/fp/transform" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "transform">; +} + +declare module "lodash/fp/unset" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "unset">; +} + +declare module "lodash/fp/dissoc" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "dissoc">; +} + +declare module "lodash/fp/dissocPath" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "dissocPath">; +} + +declare module "lodash/fp/update" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "update">; +} + +declare module "lodash/fp/updateWith" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "updateWith">; +} + +declare module "lodash/fp/values" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "values">; +} + +declare module "lodash/fp/valuesIn" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "valuesIn">; +} + +declare module "lodash/fp/tap" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "tap">; +} + +declare module "lodash/fp/thru" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "thru">; +} + +declare module "lodash/fp/camelCase" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "camelCase">; +} + +declare module "lodash/fp/capitalize" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "capitalize">; +} + +declare module "lodash/fp/deburr" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "deburr">; +} + +declare module "lodash/fp/endsWith" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "endsWith">; +} + +declare module "lodash/fp/escape" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "escape">; +} + +declare module "lodash/fp/escapeRegExp" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "escapeRegExp">; +} + +declare module "lodash/fp/kebabCase" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "kebabCase">; +} + +declare module "lodash/fp/lowerCase" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "lowerCase">; +} + +declare module "lodash/fp/lowerFirst" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "lowerFirst">; +} + +declare module "lodash/fp/pad" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "pad">; +} + +declare module "lodash/fp/padChars" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "padChars">; +} + +declare module "lodash/fp/padEnd" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "padEnd">; +} + +declare module "lodash/fp/padCharsEnd" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "padCharsEnd">; +} + +declare module "lodash/fp/padStart" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "padStart">; +} + +declare module "lodash/fp/padCharsStart" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "padCharsStart">; +} + +declare module "lodash/fp/parseInt" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "parseInt">; +} + +declare module "lodash/fp/repeat" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "repeat">; +} + +declare module "lodash/fp/replace" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "replace">; +} + +declare module "lodash/fp/snakeCase" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "snakeCase">; +} + +declare module "lodash/fp/split" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "split">; +} + +declare module "lodash/fp/startCase" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "startCase">; +} + +declare module "lodash/fp/startsWith" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "startsWith">; +} + +declare module "lodash/fp/template" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "template">; +} + +declare module "lodash/fp/toLower" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "toLower">; +} + +declare module "lodash/fp/toUpper" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "toUpper">; +} + +declare module "lodash/fp/trim" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "trim">; +} + +declare module "lodash/fp/trimChars" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "trimChars">; +} + +declare module "lodash/fp/trimEnd" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "trimEnd">; +} + +declare module "lodash/fp/trimCharsEnd" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "trimCharsEnd">; +} + +declare module "lodash/fp/trimStart" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "trimStart">; +} + +declare module "lodash/fp/trimCharsStart" { + declare module.exports: $PropertyType< + $Exports<"lodash/fp">, + "trimCharsStart" + >; +} + +declare module "lodash/fp/truncate" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "truncate">; +} + +declare module "lodash/fp/unescape" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "unescape">; +} + +declare module "lodash/fp/upperCase" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "upperCase">; +} + +declare module "lodash/fp/upperFirst" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "upperFirst">; +} + +declare module "lodash/fp/words" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "words">; +} + +declare module "lodash/fp/attempt" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "attempt">; +} + +declare module "lodash/fp/bindAll" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "bindAll">; +} + +declare module "lodash/fp/cond" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "cond">; +} + +declare module "lodash/fp/constant" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "constant">; +} + +declare module "lodash/fp/always" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "always">; +} + +declare module "lodash/fp/defaultTo" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "defaultTo">; +} + +declare module "lodash/fp/flow" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "flow">; +} + +declare module "lodash/fp/pipe" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "pipe">; +} + +declare module "lodash/fp/flowRight" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "flowRight">; +} + +declare module "lodash/fp/compose" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "compose">; +} + +declare module "lodash/fp/identity" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "identity">; +} + +declare module "lodash/fp/iteratee" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "iteratee">; +} + +declare module "lodash/fp/matches" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "matches">; +} + +declare module "lodash/fp/matchesProperty" { + declare module.exports: $PropertyType< + $Exports<"lodash/fp">, + "matchesProperty" + >; +} + +declare module "lodash/fp/propEq" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "propEq">; +} + +declare module "lodash/fp/pathEq" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "pathEq">; +} + +declare module "lodash/fp/method" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "method">; +} + +declare module "lodash/fp/methodOf" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "methodOf">; +} + +declare module "lodash/fp/mixin" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "mixin">; +} + +declare module "lodash/fp/noConflict" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "noConflict">; +} + +declare module "lodash/fp/noop" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "noop">; +} + +declare module "lodash/fp/nthArg" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "nthArg">; +} + +declare module "lodash/fp/over" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "over">; +} + +declare module "lodash/fp/juxt" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "juxt">; +} + +declare module "lodash/fp/overEvery" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "overEvery">; +} + +declare module "lodash/fp/allPass" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "allPass">; +} + +declare module "lodash/fp/overSome" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "overSome">; +} + +declare module "lodash/fp/anyPass" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "anyPass">; +} + +declare module "lodash/fp/property" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "property">; +} + +declare module "lodash/fp/propertyOf" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "propertyOf">; +} + +declare module "lodash/fp/range" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "range">; +} + +declare module "lodash/fp/rangeStep" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "rangeStep">; +} + +declare module "lodash/fp/rangeRight" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "rangeRight">; +} + +declare module "lodash/fp/rangeStepRight" { + declare module.exports: $PropertyType< + $Exports<"lodash/fp">, + "rangeStepRight" + >; +} + +declare module "lodash/fp/runInContext" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "runInContext">; +} + +declare module "lodash/fp/stubArray" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "stubArray">; +} + +declare module "lodash/fp/stubFalse" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "stubFalse">; +} + +declare module "lodash/fp/F" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "F">; +} + +declare module "lodash/fp/stubObject" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "stubObject">; +} + +declare module "lodash/fp/stubString" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "stubString">; +} + +declare module "lodash/fp/stubTrue" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "stubTrue">; +} + +declare module "lodash/fp/T" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "T">; +} + +declare module "lodash/fp/times" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "times">; +} + +declare module "lodash/fp/toPath" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "toPath">; +} + +declare module "lodash/fp/uniqueId" { + declare module.exports: $PropertyType<$Exports<"lodash/fp">, "uniqueId">; +} diff --git a/flow-typed/npm/pikaday_vx.x.x.js b/flow-typed/npm/pikaday_vx.x.x.js new file mode 100644 index 000000000..e5773cbd9 --- /dev/null +++ b/flow-typed/npm/pikaday_vx.x.x.js @@ -0,0 +1,53 @@ +// flow-typed signature: 43dc66b0844a949dcb4c6a9fa77e8d9f +// flow-typed version: <>/pikaday_v^1.7.0/flow_v0.79.0 + +/** + * This is an autogenerated libdef stub for: + * + * 'pikaday' + * + * Fill this stub out by replacing all the `any` types. + * + * Once filled out, we encourage you to share your work with the + * community by sending a pull request to: + * https://github.com/flowtype/flow-typed + */ + +declare module 'pikaday' { + declare module.exports: any; +} + +/** + * We include stubs for each file inside this npm package in case you need to + * require those files directly. Feel free to delete any files that aren't + * needed. + */ +declare module 'pikaday/pikaday' { + declare module.exports: any; +} + +declare module 'pikaday/plugins/pikaday.jquery' { + declare module.exports: any; +} + +declare module 'pikaday/tests/methods' { + declare module.exports: any; +} + +declare module 'pikaday/tests/module' { + declare module.exports: any; +} + +// Filename aliases +declare module 'pikaday/pikaday.js' { + declare module.exports: $Exports<'pikaday/pikaday'>; +} +declare module 'pikaday/plugins/pikaday.jquery.js' { + declare module.exports: $Exports<'pikaday/plugins/pikaday.jquery'>; +} +declare module 'pikaday/tests/methods.js' { + declare module.exports: $Exports<'pikaday/tests/methods'>; +} +declare module 'pikaday/tests/module.js' { + declare module.exports: $Exports<'pikaday/tests/module'>; +} diff --git a/flow-typed/npm/react-immutable-proptypes_vx.x.x.js b/flow-typed/npm/react-immutable-proptypes_vx.x.x.js new file mode 100644 index 000000000..634f63bb9 --- /dev/null +++ b/flow-typed/npm/react-immutable-proptypes_vx.x.x.js @@ -0,0 +1,39 @@ +// flow-typed signature: f20fb915e34b2032454bcd3575bb6ebc +// flow-typed version: <>/react-immutable-proptypes_v^2.1.0/flow_v0.79.0 + +/** + * This is an autogenerated libdef stub for: + * + * 'react-immutable-proptypes' + * + * Fill this stub out by replacing all the `any` types. + * + * Once filled out, we encourage you to share your work with the + * community by sending a pull request to: + * https://github.com/flowtype/flow-typed + */ + +declare module 'react-immutable-proptypes' { + declare module.exports: any; +} + +/** + * We include stubs for each file inside this npm package in case you need to + * require those files directly. Feel free to delete any files that aren't + * needed. + */ +declare module 'react-immutable-proptypes/dist/ImmutablePropTypes' { + declare module.exports: any; +} + +declare module 'react-immutable-proptypes/src/ImmutablePropTypes' { + declare module.exports: any; +} + +// Filename aliases +declare module 'react-immutable-proptypes/dist/ImmutablePropTypes.js' { + declare module.exports: $Exports<'react-immutable-proptypes/dist/ImmutablePropTypes'>; +} +declare module 'react-immutable-proptypes/src/ImmutablePropTypes.js' { + declare module.exports: $Exports<'react-immutable-proptypes/src/ImmutablePropTypes'>; +} diff --git a/flow-typed/npm/react-intl_v2.x.x.js b/flow-typed/npm/react-intl_v2.x.x.js new file mode 100644 index 000000000..0b679534a --- /dev/null +++ b/flow-typed/npm/react-intl_v2.x.x.js @@ -0,0 +1,262 @@ +// flow-typed signature: c3aa29455eb7f759ba4d433975a4ec02 +// flow-typed version: b14d5b4826/react-intl_v2.x.x/flow_>=v0.63.x + +/** + * Original implementation of this file by @marudor at https://github.com/marudor/flowInterfaces + * Copied here based on intention to merge with flow-typed expressed here: + * https://github.com/marudor/flowInterfaces/issues/6 + */ +// Mostly from https://github.com/yahoo/react-intl/wiki/API#react-intl-api +declare module "react-intl" { + import type { Element, ChildrenArray } from "react"; + + declare type $npm$ReactIntl$LocaleData = { + locale: string, + [key: string]: any + }; + + declare type $npm$ReactIntl$MessageDescriptor = { + id: string, + description?: string, + defaultMessage?: string + }; + + declare type $npm$ReactIntl$IntlConfig = { + locale: string, + formats: Object, + messages: { [id: string]: string }, + + defaultLocale?: string, + defaultFormats?: Object + }; + + declare type $npm$ReactIntl$IntlProviderConfig = { + locale?: string, + formats?: Object, + messages?: { [id: string]: string }, + + defaultLocale?: string, + defaultFormats?: Object + }; + + declare type $npm$ReactIntl$IntlFormat = { + formatDate: (value: any, options?: Object) => string, + formatTime: (value: any, options?: Object) => string, + formatRelative: (value: any, options?: Object) => string, + formatNumber: (value: any, options?: Object) => string, + formatPlural: (value: any, options?: Object) => string, + formatMessage: ( + messageDescriptor: $npm$ReactIntl$MessageDescriptor, + values?: Object + ) => string, + formatHTMLMessage: ( + messageDescriptor: $npm$ReactIntl$MessageDescriptor, + values?: Object + ) => string + }; + + declare type $npm$ReactIntl$IntlShape = $npm$ReactIntl$IntlConfig & + $npm$ReactIntl$IntlFormat & { now: () => number }; + + declare type $npm$ReactIntl$DateTimeFormatOptions = { + localeMatcher?: "best fit" | "lookup", + formatMatcher?: "basic" | "best fit", + + timeZone?: string, + hour12?: boolean, + + weekday?: "narrow" | "short" | "long", + era?: "narrow" | "short" | "long", + year?: "numeric" | "2-digit", + month?: "numeric" | "2-digit" | "narrow" | "short" | "long", + day?: "numeric" | "2-digit", + hour?: "numeric" | "2-digit", + minute?: "numeric" | "2-digit", + second?: "numeric" | "2-digit", + timeZoneName?: "short" | "long" + }; + + declare type $npm$ReactIntl$RelativeFormatOptions = { + style?: "best fit" | "numeric", + units?: "second" | "minute" | "hour" | "day" | "month" | "year" + }; + + declare type $npm$ReactIntl$NumberFormatOptions = { + localeMatcher?: "best fit" | "lookup", + + style?: "decimal" | "currency" | "percent", + + currency?: string, + currencyDisplay?: "symbol" | "code" | "name", + + useGrouping?: boolean, + + minimumIntegerDigits?: number, + minimumFractionDigits?: number, + maximumFractionDigits?: number, + minimumSignificantDigits?: number, + maximumSignificantDigits?: number + }; + + declare type $npm$ReactIntl$PluralFormatOptions = { + style?: "cardinal" | "ordinal" + }; + + declare type $npm$ReactIntl$PluralCategoryString = + | "zero" + | "one" + | "two" + | "few" + | "many" + | "other"; + + declare type $npm$ReactIntl$DateParseable = number | string | Date; + // PropType checker + declare function intlShape( + props: Object, + propName: string, + componentName: string + ): void; + declare function addLocaleData( + data: $npm$ReactIntl$LocaleData | Array<$npm$ReactIntl$LocaleData> + ): void; + declare function defineMessages< + T: { [key: string]: $npm$ReactIntl$MessageDescriptor } + >( + messageDescriptors: T + ): T; + + declare type InjectIntlProvidedProps = { + intl: $npm$ReactIntl$IntlShape + } + + declare type InjectIntlVoidProps = { + intl: $npm$ReactIntl$IntlShape | void + } + + declare type ComponentWithDefaultProps = + | React$ComponentType + | React$StatelessFunctionalComponent + | ChildrenArray>; + + declare type InjectIntlOptions = { + intlPropName?: string, + withRef?: boolean + } + + declare class IntlInjectedComponent extends React$Component { + static WrappedComponent: Class>, + static defaultProps: TDefaultProps, + props: TOwnProps + } + + declare type IntlInjectedComponentClass = Class< + IntlInjectedComponent + >; + + declare function injectIntl>( + WrappedComponent: Component, + options?: InjectIntlOptions, + ): React$ComponentType< + $Diff, InjectIntlVoidProps> + >; + + declare function formatMessage( + messageDescriptor: $npm$ReactIntl$MessageDescriptor, + values?: Object + ): string; + declare function formatHTMLMessage( + messageDescriptor: $npm$ReactIntl$MessageDescriptor, + values?: Object + ): string; + declare function formatDate( + value: any, + options?: $npm$ReactIntl$DateTimeFormatOptions & { format: string } + ): string; + declare function formatTime( + value: any, + options?: $npm$ReactIntl$DateTimeFormatOptions & { format: string } + ): string; + declare function formatRelative( + value: any, + options?: $npm$ReactIntl$RelativeFormatOptions & { + format: string, + now: any + } + ): string; + declare function formatNumber( + value: any, + options?: $npm$ReactIntl$NumberFormatOptions & { format: string } + ): string; + declare function formatPlural( + value: any, + options?: $npm$ReactIntl$PluralFormatOptions + ): $npm$ReactIntl$PluralCategoryString; + + declare class FormattedMessage extends React$Component< + $npm$ReactIntl$MessageDescriptor & { + values?: Object, + tagName?: string, + children?: + | ((...formattedMessage: Array) => React$Node) + | (string => React$Node) + } + > {} + declare class FormattedHTMLMessage extends React$Component< + $npm$ReactIntl$DateTimeFormatOptions & { + values?: Object, + tagName?: string, + children?: (...formattedMessage: Array) => React$Node + } + > {} + declare class FormattedDate extends React$Component< + $npm$ReactIntl$DateTimeFormatOptions & { + value: $npm$ReactIntl$DateParseable, + format?: string, + children?: (formattedDate: string) => React$Node + } + > {} + declare class FormattedTime extends React$Component< + $npm$ReactIntl$DateTimeFormatOptions & { + value: $npm$ReactIntl$DateParseable, + format?: string, + children?: (formattedDate: string) => React$Node + } + > {} + declare class FormattedRelative extends React$Component< + $npm$ReactIntl$RelativeFormatOptions & { + value: $npm$ReactIntl$DateParseable, + format?: string, + updateInterval?: number, + initialNow?: $npm$ReactIntl$DateParseable, + children?: (formattedDate: string) => React$Node + } + > {} + declare class FormattedNumber extends React$Component< + $npm$ReactIntl$NumberFormatOptions & { + value: number | string, + format?: string, + children?: (formattedNumber: string) => React$Node + } + > {} + declare class FormattedPlural extends React$Component< + $npm$ReactIntl$PluralFormatOptions & { + value: number | string, + other: React$Node, + zero?: React$Node, + one?: React$Node, + two?: React$Node, + few?: React$Node, + many?: React$Node, + children?: (formattedPlural: React$Node) => React$Node + } + > {} + declare class IntlProvider extends React$Component< + $npm$ReactIntl$IntlProviderConfig & { + children?: React$Node, + initialNow?: $npm$ReactIntl$DateParseable + } + > {} + declare type IntlShape = $npm$ReactIntl$IntlShape; + declare type MessageDescriptor = $npm$ReactIntl$MessageDescriptor; +} diff --git a/flow-typed/npm/react-process-string_vx.x.x.js b/flow-typed/npm/react-process-string_vx.x.x.js new file mode 100644 index 000000000..36552494d --- /dev/null +++ b/flow-typed/npm/react-process-string_vx.x.x.js @@ -0,0 +1,38 @@ +// flow-typed signature: 477c7f722a99d32f42a5f04c782746f5 +// flow-typed version: <>/react-process-string_v^1.2.0/flow_v0.79.0 + +/** + * This is an autogenerated libdef stub for: + * + * 'react-process-string' + * + * Fill this stub out by replacing all the `any` types. + * + * Once filled out, we encourage you to share your work with the + * community by sending a pull request to: + * https://github.com/flowtype/flow-typed + */ + +declare module 'react-process-string' { + declare module.exports: any; +} + +/** + * We include stubs for each file inside this npm package in case you need to + * require those files directly. Feel free to delete any files that aren't + * needed. + */ +declare module 'react-process-string/dist/index' { + declare module.exports: any; +} + +// Filename aliases +declare module 'react-process-string/dist/index.js' { + declare module.exports: $Exports<'react-process-string/dist/index'>; +} +declare module 'react-process-string/index' { + declare module.exports: $Exports<'react-process-string'>; +} +declare module 'react-process-string/index.js' { + declare module.exports: $Exports<'react-process-string'>; +} diff --git a/flow-typed/npm/react-textarea-autosize_vx.x.x.js b/flow-typed/npm/react-textarea-autosize_vx.x.x.js new file mode 100644 index 000000000..2814d103a --- /dev/null +++ b/flow-typed/npm/react-textarea-autosize_vx.x.x.js @@ -0,0 +1,67 @@ +// flow-typed signature: ab5e66dd46a302a12a22e4c165eecc71 +// flow-typed version: <>/react-textarea-autosize_v^7.0.4/flow_v0.79.0 + +/** + * This is an autogenerated libdef stub for: + * + * 'react-textarea-autosize' + * + * Fill this stub out by replacing all the `any` types. + * + * Once filled out, we encourage you to share your work with the + * community by sending a pull request to: + * https://github.com/flowtype/flow-typed + */ + +declare module 'react-textarea-autosize' { + declare module.exports: any; +} + +/** + * We include stubs for each file inside this npm package in case you need to + * require those files directly. Feel free to delete any files that aren't + * needed. + */ +declare module 'react-textarea-autosize/dist/react-textarea-autosize.cjs.browser' { + declare module.exports: any; +} + +declare module 'react-textarea-autosize/dist/react-textarea-autosize.cjs' { + declare module.exports: any; +} + +declare module 'react-textarea-autosize/dist/react-textarea-autosize.esm.browser' { + declare module.exports: any; +} + +declare module 'react-textarea-autosize/dist/react-textarea-autosize.esm' { + declare module.exports: any; +} + +declare module 'react-textarea-autosize/dist/react-textarea-autosize' { + declare module.exports: any; +} + +declare module 'react-textarea-autosize/dist/react-textarea-autosize.min' { + declare module.exports: any; +} + +// Filename aliases +declare module 'react-textarea-autosize/dist/react-textarea-autosize.cjs.browser.js' { + declare module.exports: $Exports<'react-textarea-autosize/dist/react-textarea-autosize.cjs.browser'>; +} +declare module 'react-textarea-autosize/dist/react-textarea-autosize.cjs.js' { + declare module.exports: $Exports<'react-textarea-autosize/dist/react-textarea-autosize.cjs'>; +} +declare module 'react-textarea-autosize/dist/react-textarea-autosize.esm.browser.js' { + declare module.exports: $Exports<'react-textarea-autosize/dist/react-textarea-autosize.esm.browser'>; +} +declare module 'react-textarea-autosize/dist/react-textarea-autosize.esm.js' { + declare module.exports: $Exports<'react-textarea-autosize/dist/react-textarea-autosize.esm'>; +} +declare module 'react-textarea-autosize/dist/react-textarea-autosize.js' { + declare module.exports: $Exports<'react-textarea-autosize/dist/react-textarea-autosize'>; +} +declare module 'react-textarea-autosize/dist/react-textarea-autosize.min.js' { + declare module.exports: $Exports<'react-textarea-autosize/dist/react-textarea-autosize.min'>; +} diff --git a/flow-typed/npm/scroll-into-view-if-needed_vx.x.x.js b/flow-typed/npm/scroll-into-view-if-needed_vx.x.x.js new file mode 100644 index 000000000..50b81ee60 --- /dev/null +++ b/flow-typed/npm/scroll-into-view-if-needed_vx.x.x.js @@ -0,0 +1,59 @@ +// flow-typed signature: ef12d4a1d1a2d98acc89083c86b64481 +// flow-typed version: <>/scroll-into-view-if-needed_v^2.2.16/flow_v0.79.0 + +/** + * This is an autogenerated libdef stub for: + * + * 'scroll-into-view-if-needed' + * + * Fill this stub out by replacing all the `any` types. + * + * Once filled out, we encourage you to share your work with the + * community by sending a pull request to: + * https://github.com/flowtype/flow-typed + */ + +declare module 'scroll-into-view-if-needed' { + declare module.exports: any; +} + +/** + * We include stubs for each file inside this npm package in case you need to + * require those files directly. Feel free to delete any files that aren't + * needed. + */ +declare module 'scroll-into-view-if-needed/es/index' { + declare module.exports: any; +} + +declare module 'scroll-into-view-if-needed/es/types' { + declare module.exports: any; +} + +declare module 'scroll-into-view-if-needed/umd/scroll-into-view-if-needed' { + declare module.exports: any; +} + +declare module 'scroll-into-view-if-needed/umd/scroll-into-view-if-needed.min' { + declare module.exports: any; +} + +// Filename aliases +declare module 'scroll-into-view-if-needed/es/index.js' { + declare module.exports: $Exports<'scroll-into-view-if-needed/es/index'>; +} +declare module 'scroll-into-view-if-needed/es/types.js' { + declare module.exports: $Exports<'scroll-into-view-if-needed/es/types'>; +} +declare module 'scroll-into-view-if-needed/index' { + declare module.exports: $Exports<'scroll-into-view-if-needed'>; +} +declare module 'scroll-into-view-if-needed/index.js' { + declare module.exports: $Exports<'scroll-into-view-if-needed'>; +} +declare module 'scroll-into-view-if-needed/umd/scroll-into-view-if-needed.js' { + declare module.exports: $Exports<'scroll-into-view-if-needed/umd/scroll-into-view-if-needed'>; +} +declare module 'scroll-into-view-if-needed/umd/scroll-into-view-if-needed.min.js' { + declare module.exports: $Exports<'scroll-into-view-if-needed/umd/scroll-into-view-if-needed.min'>; +} diff --git a/flow/DraftJSFlowStub.js.flow b/flow/DraftJSFlowStub.js.flow new file mode 100644 index 000000000..489e7ef4b --- /dev/null +++ b/flow/DraftJSFlowStub.js.flow @@ -0,0 +1,4 @@ +// @flow +declare export var EditorState: any +declare export var ContentState: any +declare export default {} diff --git a/flow/Rangy.js.flow b/flow/Rangy.js.flow new file mode 100644 index 000000000..46f22c301 --- /dev/null +++ b/flow/Rangy.js.flow @@ -0,0 +1,4 @@ +declare export var rangy: any +declare export var rangyClassApplier: any +declare export var rangyHighlight: any +declare export var rangySaveRestore: any \ No newline at end of file diff --git a/flow/SCSSFlowStub.js.flow b/flow/SCSSFlowStub.js.flow new file mode 100644 index 000000000..d0af69ce8 --- /dev/null +++ b/flow/SCSSFlowStub.js.flow @@ -0,0 +1,2 @@ +// @flow +declare export default {} diff --git a/flow/WebpackI18N.js.flow b/flow/WebpackI18N.js.flow new file mode 100644 index 000000000..292cdda06 --- /dev/null +++ b/flow/WebpackI18N.js.flow @@ -0,0 +1,2 @@ +// @flow +declare export default { [key: string]: string } \ No newline at end of file diff --git a/i18n/en-US.js b/i18n/en-US.js new file mode 100644 index 000000000..68021da04 --- /dev/null +++ b/i18n/en-US.js @@ -0,0 +1,22 @@ +export default { + "ba.anonymousUserName": "Some User", + "ba.whoAnnotated": "{name} annotated", + "ba.whoDrew": "{name} drew", + "ba.whoHighlighted": "{name} highlighted", + "be.approvalAddTask": "Add Task", + "be.approvalAddTaskTooltip": "Assigning a task to someone will send them a notification with the message in the comment box and allow them to approve or deny.", + "be.approvalAssignees": "Assignees", + "be.approvalDueDate": "Due Date", + "be.approvalSelectDate": "Select a date", + "be.atMentionTip": "@mention users to notify them.", + "be.commentCancel": "Cancel", + "be.commentDeleteCancel": "No", + "be.commentDeleteConfirm": "Yes", + "be.commentDeletePrompt": "Delete comment?", + "be.commentPost": "Post", + "be.commentPostedFullDateTime": "{time, date, full} at {time, time, short}", + "be.commentShowOriginal": "Show Original", + "be.commentTranslate": "Translate", + "be.commentWrite": "Write a comment", + "be.deleteLabel": "Delete" +} \ No newline at end of file diff --git a/i18n/en-US.properties b/i18n/en-US.properties new file mode 100644 index 000000000..d5ff763a6 --- /dev/null +++ b/i18n/en-US.properties @@ -0,0 +1,40 @@ +# Placeholder when the current annotation's user information is unknown +ba.anonymousUserName = Some User +# Label for who left the annotation +ba.whoAnnotated = {name} annotated +# Label for who drew the drawing annotation +ba.whoDrew = {name} drew +# Label for who highlighted the annotated text +ba.whoHighlighted = {name} highlighted +# Label for checkbox to add approvers to a comment +be.approvalAddTask = Add Task +# Tooltip text for checkbox to add approvers to a comment +be.approvalAddTaskTooltip = Assigning a task to someone will send them a notification with the message in the comment box and allow them to approve or deny. +# Title for assignees input +be.approvalAssignees = Assignees +# Title for approvers due date input +be.approvalDueDate = Due Date +# Placeholder for due date input +be.approvalSelectDate = Select a date +# Mentioning call to action displayed below the comment input +be.atMentionTip = @mention users to notify them. +# Text for cancel button +be.commentCancel = Cancel +# Button text to cancel comment deletion +be.commentDeleteCancel = No +# Button text to confirm comment deletion +be.commentDeleteConfirm = Yes +# Confirmation prompt text to delete comment +be.commentDeletePrompt = Delete comment? +# Text for post button +be.commentPost = Post +# Comment posted full date time for title +be.commentPostedFullDateTime = {time, date, full} at {time, time, short} +# Show original button for showing original comment +be.commentShowOriginal = Show Original +# Translate button for translating comment +be.commentTranslate = Translate +# Placeholder for comment input +be.commentWrite = Write a comment +# Aria label for button to delete a comment or task +be.deleteLabel = Delete diff --git a/i18n/json/src/components/AnnotationPopover/messages.json b/i18n/json/src/components/AnnotationPopover/messages.json new file mode 100644 index 000000000..613ac03e1 --- /dev/null +++ b/i18n/json/src/components/AnnotationPopover/messages.json @@ -0,0 +1,22 @@ +[ + { + "id": "ba.anonymousUserName", + "description": "Placeholder when the current annotation's user information is unknown", + "defaultMessage": "Some User" + }, + { + "id": "ba.whoHighlighted", + "description": "Label for who highlighted the annotated text", + "defaultMessage": "{name} highlighted" + }, + { + "id": "ba.whoDrew", + "description": "Label for who drew the drawing annotation", + "defaultMessage": "{name} drew" + }, + { + "id": "ba.whoAnnotated", + "description": "Label for who left the annotation", + "defaultMessage": "{name} annotated" + } +] \ No newline at end of file diff --git a/i18n/json/third-party/messages.json b/i18n/json/third-party/messages.json new file mode 100644 index 000000000..2455370ac --- /dev/null +++ b/i18n/json/third-party/messages.json @@ -0,0 +1,82 @@ +[ + { + "id": "be.approvalAddTask", + "description": "Label for checkbox to add approvers to a comment", + "defaultMessage": "Add Task" + }, + { + "id": "be.approvalAddTaskTooltip", + "description": "Tooltip text for checkbox to add approvers to a comment", + "defaultMessage": "Assigning a task to someone will send them a notification with the message in the comment box and allow them to approve or deny." + }, + { + "id": "be.approvalAssignees", + "description": "Title for assignees input", + "defaultMessage": "Assignees" + }, + { + "id": "be.approvalDueDate", + "description": "Title for approvers due date input", + "defaultMessage": "Due Date" + }, + { + "id": "be.approvalSelectDate", + "description": "Placeholder for due date input", + "defaultMessage": "Select a date" + }, + { + "id": "be.atMentionTip", + "description": "Mentioning call to action displayed below the comment input", + "defaultMessage": "@mention users to notify them." + }, + { + "id": "be.commentPostedFullDateTime", + "description": "Comment posted full date time for title", + "defaultMessage": "{time, date, full} at {time, time, short}" + }, + { + "id": "be.commentCancel", + "description": "Text for cancel button", + "defaultMessage": "Cancel" + }, + { + "id": "be.commentDeleteCancel", + "description": "Button text to cancel comment deletion", + "defaultMessage": "No" + }, + { + "id": "be.commentDeleteConfirm", + "description": "Button text to confirm comment deletion", + "defaultMessage": "Yes" + }, + { + "id": "be.commentDeletePrompt", + "description": "Confirmation prompt text to delete comment", + "defaultMessage": "Delete comment?" + }, + { + "id": "be.commentPost", + "description": "Text for post button", + "defaultMessage": "Post" + }, + { + "id": "be.commentShowOriginal", + "description": "Show original button for showing original comment", + "defaultMessage": "Show Original" + }, + { + "id": "be.commentTranslate", + "description": "Translate button for translating comment", + "defaultMessage": "Translate" + }, + { + "id": "be.commentWrite", + "description": "Placeholder for comment input", + "defaultMessage": "Write a comment" + }, + { + "id": "be.deleteLabel", + "description": "Aria label for button to delete a comment or task", + "defaultMessage": "Delete" + } +] \ No newline at end of file diff --git a/package.json b/package.json index 343075dc9..7b6478e37 100644 --- a/package.json +++ b/package.json @@ -8,78 +8,127 @@ "type": "git", "url": "git@github.com:box/box-annotations.git" }, + "bugs": { + "url": "https://github.com/box/box-annotations/issues" + }, "publishConfig": { "registry": "https://registry.npmjs.org/" }, + "devEngines": { + "node": ">=8.x", + "npm": ">=3.x", + "yarn": ">=1.0.0" + }, "peerDependencies": { - "box-react-ui": "^25.12.0" + "box-react-ui": "^26.1.1", + "draft-js": "^0.10.5", + "form-serialize": "^0.7.2", + "immutable": "^3.7.4", + "lodash": "^4.17.10", + "react": "^16.4.2", + "react-dom": "^16.3.1", + "react-immutable-proptypes": "^2.1.0", + "react-intl": "^2.4.0", + "react-process-string": "^1.2.0", + "react-textarea-autosize": "^7.0.4", + "scroll-into-view-if-needed": "^2.2.16" }, "devDependencies": { "autoprefixer": "^9.1.3", + "axios": "^0.18.0", "babel-cli": "^6.26.0", "babel-core": "^6.26.3", "babel-eslint": "^8.2.6", "babel-jest": "^23.4.2", "babel-loader": "^7.1.5", + "babel-plugin-flow-react-proptypes": "^24.1.1", + "babel-plugin-react-intl": "^2.4.0", "babel-plugin-transform-class-properties": "^6.24.1", "babel-plugin-transform-decorators-legacy": "^1.3.5", "babel-plugin-transform-object-rest-spread": "^6.26.0", "babel-plugin-transform-require-ignore": "^0.1.1", "babel-polyfill": "^6.26.0", + "babel-preset-env": "^1.7.0", "babel-preset-es2015": "^6.24.1", "babel-preset-es2016": "^6.24.1", + "babel-preset-flow": "^6.23.0", "babel-preset-react": "^6.24.1", + "babel-preset-stage-1": "^6.24.1", "bluebird": "^3.5.2", + "box-locales": "^0.0.1", "box-node-sdk": "^1.22.0", - "box-react-ui": "^25.12.0", + "box-react-ui": "^26.1.1", "chai": "^4.1.2", "chai-dom": "^1.8.0", + "circular-dependency-plugin": "^5.0.2", + "classnames": "^2.2.5", "codeceptjs-webdriverio": "^1.1.0", "commitlint": "^7.0.0", "conventional-changelog-cli": "^2.0.5", "conventional-github-releaser": "^3.1.2", + "core-js": "^2.5.7", "css-loader": "^1.0.0", "cssnano-cli": "^1.0.5", + "draft-js": "^0.10.5", + "enzyme": "^3.4.4", + "enzyme-adapter-react-16": "^1.2.0", "enzyme-to-json": "^3.3.4", "eslint": "^5.4.0", "eslint-config-airbnb": "^17.1.0", "eslint-config-prettier": "^3.0.1", "eslint-import-resolver-webpack": "^0.10.1", "eslint-plugin-babel": "^5.1.0", + "eslint-plugin-flowtype": "^2.46.1", "eslint-plugin-import": "^2.14.0", "eslint-plugin-jsx-a11y": "^6.1.1", "eslint-plugin-react": "^7.11.1", "extract-text-webpack-plugin": "^3.0.2", "fetch-mock": "^6.5.2", "fetch-mock-forwarder": "^1.0.0", + "flow-bin": "^0.79.0", + "flow-typed": "^2.5.1", + "form-serialize": "^0.7.2", "husky": "^0.14.3", + "immutable": "^3.7.4", "jest": "^23.5.0", "jest-canvas-mock": "^1.1.0", "jws": "^3.1.5", "lint-staged": "^7.2.2", "mini-css-extract-plugin": "^0.4.2", "mocha": "^5.2.0", - "node-fetch": "^2.2.0", - "node-noop": "^1.0.0", "node-sass": "^4.9.3", "nsp": "^3.2.1", "optimize-css-assets-webpack-plugin": "^4.0.2", + "pikaday": "^1.8.0", "postcss-loader": "^3.0.0", "prettier": "^1.14.2", "prettier-eslint-cli": "^4.4.2", + "prop-types": "^15.6.1", + "properties-parser": "^0.3.1", "pug": "^2.0.3", "pug-code-gen": "^2.0.1", "pug-filters": "^3.1.0", "pug-lexer": "^4.0.0", + "raf": "^3.4.0", "rangy": "^1.3.0", "raw-loader": "^0.5.1", "rbush": "^2.0.1", + "react": "^16.4.2", + "react-dom": "^16.3.1", + "react-immutable-proptypes": "^2.1.0", + "react-intl": "^2.4.0", + "react-process-string": "^1.2.0", + "react-styleguidist": "^7.3.0", + "react-tether": "^1.0.1", + "react-textarea-autosize": "^7.0.4", "sass-loader": "^7.1.0", + "scroll-into-view-if-needed": "^2.2.16", "style-loader": "^0.23.0", "stylelint": "^9.5.0", "stylelint-config-standard": "^18.0.0", "stylelint-order": "^1.0.0", "stylelint-scss": "^3.3.0", + "tabbable": "^3.1.1", "uglifyjs-webpack-plugin": "^1.3.0", "webpack": "^4.12.0", "webpack-bundle-analyzer": "^2.13.1", @@ -87,28 +136,37 @@ "whatwg-fetch": "^2.0.3" }, "scripts": { - "build": "yarn install && BABEL_ENV=production NODE_ENV=production CI=1 node --max_old_space_size=4096 ./node_modules/webpack/bin/webpack.js -p --progress --colors --config build/webpack.config.js", - "watch": "yarn install && BABEL_ENV=dev NODE_ENV=dev ./node_modules/.bin/webpack --watch --progress --colors --config build/webpack.config.js", + "build": "yarn install && LANGUAGE=en-US BABEL_ENV=production NODE_ENV=production CI=1 node --max_old_space_size=4096 ./node_modules/webpack/bin/webpack.js -p --progress --colors --config build/webpack.config.js", + "build-locales": "node ./build/props-to-es2015.js", + "build-prod": "BABEL_ENV=production NODE_ENV=production webpack --config build/webpack.config.js --mode production", + "build-variables": "node ./build/build-style-vars.js ./src/styles/_variables.scss ./src/styles/variables.js ./src/styles/variables.json", + "watch": "yarn install && LANGUAGE=en-US BABEL_ENV=dev NODE_ENV=dev ./node_modules/.bin/webpack --watch --progress --colors --config build/webpack.config.js --mode development", "test": "yarn install && NODE_ENV=test yarn run jest", "debug": "yarn install && NODE_ENV=test yarn run jest --watch", "setup-travis": "cd functional-tests && yarn install && node app.js", - "selenium-build": "BABEL_ENV=production NODE_ENV=production CI=1 node --max_old_space_size=4096 ./node_modules/webpack/bin/webpack.js -p --progress --colors --config build/webpack.selenium.config.js", + "selenium-build": "LANGUAGE=en-US BABEL_ENV=production NODE_ENV=production CI=1 node --max_old_space_size=4096 ./node_modules/webpack/bin/webpack.js -p --progress --colors --config build/webpack.selenium.config.js", "functional-tests": "node functional-tests/app.js & node ./node_modules/codeceptjs/bin/codecept.js run --steps", - "functional-tests-ci": "yarn run clean && yarn run selenium-build && node ./node_modules/codeceptjs/bin/codecept.js run --steps", + "functional-tests-ci": "yarn run pre-build && yarn run selenium-build && node ./node_modules/codeceptjs/bin/codecept.js run --steps", "lint": "NODE_ENV=dev ./node_modules/.bin/eslint src && ./node_modules/.bin/stylelint 'src/**/*.scss'", "precommit": "lint-staged", "commitmsg": "commitlint -e", - "prepush": "yarn run lint", + "prepush": "./build/prepush.sh", + "pre-build": "yarn install && yarn run clean && yarn run build-locales", + "flow": "flow check", + "flow-typed": "flow-typed", + "flow-typed-update": "yarn add flow-typed && yarn run flow-typed update -i dev", "prettier": "prettier-eslint \"src/**/*.js\" --print-width 120 --single-quote --tab-width 4 --write", - "ci": "yarn nsp && yarn run clean && yarn run lint && yarn install && yarn run test", - "clean": "rm -rf lib rm -rf functional-tests/lib && rm -rf reports/coverage", + "ci": "yarn nsp && yarn run pre-build && yarn run lint && yarn install && yarn run test", + "clean": "rm -rf lib functional-tests/lib reports/* i18n/json i18n/*.js styleguide", "github-release": "./node_modules/.bin/conventional-github-releaser", "changelog": "./node_modules/.bin/conventional-changelog -i CHANGELOG.md --same-file", "minor": "./build/release.sh -n && ./build/publish.sh", "major": "./build/release.sh -m && ./build/publish.sh", "patch": "./build/release.sh -p && ./build/publish.sh", "nsp": "nsp check --reporter summary", - "upgrade-brui": "./build/upgrade_brui.sh" + "upgrade-brui": "./build/upgrade_brui.sh", + "styleguide": "yarn run pre-build && LANGUAGE=en-US REACT=true BABEL_ENV=dev NODE_ENV=dev node --max_old_space_size=8192 node_modules/react-styleguidist/bin/styleguidist.js server --config build/styleguide.config.js --mode development", + "styleguide-static": "LANGUAGE=en-US REACT=true BABEL_ENV=production NODE_ENV=production node --max_old_space_size=8192 node_modules/react-styleguidist/bin/styleguidist.js build --config build/styleguide.config.js --mode production" }, "lint-staged": { "src/**/*.js": [ @@ -120,12 +178,18 @@ "clearMocks": true, "globals": { "__NAME__": "name", - "__VERSION__": "version" + "__VERSION__": "version", + "__LANGUAGE__": "en-US" }, "setupFiles": [ "jest-canvas-mock" ], "moduleNameMapper": { + "react-intl": "/test-utils/react-intl-mocks.js", + "intl": "/test-utils/lib-intl-mock.js", + "react-intl-locale-data": "/node_modules/react-intl/locale-data/en.js", + "box-annotations-locale-data": "/test-utils/i18nMock.js", + "box-react-ui-locale-data": "/test-utils/i18nMock.js", "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/test-utils/fileMock.js", "\\.(css|less|html)$": "/test-utils/styleMock.js" }, @@ -138,6 +202,13 @@ "src/**/*.js", "!**/node_modules/**", "!**/__tests__/**" + ], + "setupTestFrameworkScriptFile": "/build/enzyme-adapter.js", + "snapshotSerializers": [ + "enzyme-to-json/serializer" ] + }, + "resolutions": { + "uglify-es": "3.3.4" } } diff --git a/src/Annotation.js b/src/Annotation.js deleted file mode 100644 index e8411e331..000000000 --- a/src/Annotation.js +++ /dev/null @@ -1,48 +0,0 @@ -class Annotation { - //-------------------------------------------------------------------------- - // Typedef - //-------------------------------------------------------------------------- - - /** - * The data object for constructing an annotation. - * - * @typedef {Object} AnnotationData - * @property {string} annotationID Annotation ID - * @property {string} fileVersionId File version ID for this annotation - * @property {string} threadID Thread ID - * @property {string} thread Thread number - * @property {string} type Annotation type, e.g. 'point' or 'highlight' - * @property {string} text Annotation text - * @property {Object} location Location object - * @property {Object} user User creating/that created this annotation - * @property {Object} permissions Permissions user has - * @property {number} created Created timestamp - * @property {number} modified Modified timestamp - */ - - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- - - /** - * [constructor] - * - * @param {AnnotationData} data - Data for constructing annotation - * @return {Annotation} Instance of annotation - */ - constructor(data) { - this.annotationID = data.annotationID; - this.fileVersionId = data.fileVersionId; - this.threadID = data.threadID; - this.threadNumber = data.threadNumber; - this.type = data.type; - this.text = data.text; - this.location = data.location; - this.user = data.user; - this.permissions = data.permissions; - this.created = data.created; - this.modified = data.modified; - } -} - -export default Annotation; diff --git a/src/AnnotationDialog.js b/src/AnnotationDialog.js deleted file mode 100644 index 25bbcb404..000000000 --- a/src/AnnotationDialog.js +++ /dev/null @@ -1,978 +0,0 @@ -import EventEmitter from 'events'; -import * as util from './util'; -import * as constants from './constants'; -import { ICON_DELETE } from './icons/icons'; - -const POINT_ANNOTATION_ICON_HEIGHT = 31; -const POINT_ANNOTATION_ICON_DOT_HEIGHT = 8; -const CLASS_FLIPPED_DIALOG = 'ba-annotation-dialog-flipped'; - -const CLASS_CANCEL_DELETE = 'cancel-delete-btn'; -const CLASS_COMMENT = 'annotation-comment'; -const CLASS_COMMENTS_CONTAINER = 'annotation-comments'; -const CLASS_REPLY_CONTAINER = 'reply-container'; -const CLASS_REPLY_TEXTAREA = 'reply-textarea'; -const CLASS_BUTTON_DELETE_COMMENT = 'delete-comment-btn'; -const CLASS_DELETE_CONFIRMATION = 'delete-confirmation'; -const CLASS_BUTTON_DELETE_CONFIRM = 'confirm-delete-btn'; - -class AnnotationDialog extends EventEmitter { - //-------------------------------------------------------------------------- - // Typedef - //-------------------------------------------------------------------------- - - /** - * The data object for constructing a dialog. - * - * @typedef {Object} AnnotationDialogData - * @property {HTMLElement} annotatedElement HTML element being annotated on - * @property {Object} annotations Annotations in dialog, can be an - * empty array for a new thread - * @property {Object} location Location object - * @property {boolean} canAnnotate Whether or not user can annotate - */ - - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- - - /** - * [constructor] - * - * @param {AnnotationDialogData} data Data for constructing thread - * @return {AnnotationDialog} Annotation dialog instance - */ - constructor(data) { - super(); - - this.annotatedElement = data.annotatedElement; - this.container = data.container; - this.location = data.location; - this.hasAnnotations = Object.keys(data.annotations).length > 0; - this.canAnnotate = data.canAnnotate; - this.locale = data.locale; - this.isMobile = data.isMobile || false; - this.hasTouch = data.hasTouch || false; - - // Explicitly bind listeners - this.keydownHandler = this.keydownHandler.bind(this); - this.clickHandler = this.clickHandler.bind(this); - this.stopPropagation = this.stopPropagation.bind(this); - this.validateTextArea = this.validateTextArea.bind(this); - } - - /** - * [destructor] - * - * @return {void} - */ - destroy() { - if (this.element) { - this.unbindDOMListeners(); - - if (this.element.parentNode) { - this.element.parentNode.removeChild(this.element); - } - - this.element = null; - } - } - - /** - * Positions and shows the dialog. - * - * @return {void} - */ - show() { - // Populate mobile annotations dialog with annotations information - if (this.isMobile) { - this.showMobileDialog(); - } else if (this.element && !this.element.classList.contains(constants.CLASS_HIDDEN)) { - // Do not re-show dialog if it is already visible - return; - } - - const textAreaEl = this.hasAnnotations - ? this.element.querySelector(`.${CLASS_REPLY_TEXTAREA}`) - : this.element.querySelector(constants.SELECTOR_ANNOTATION_TEXTAREA); - - if (this.canAnnotate) { - // Don't re-position if reply textarea is already active - const textareaIsActive = textAreaEl.classList.contains(constants.CLASS_ACTIVE); - if (textareaIsActive && this.element.parentNode) { - util.showElement(this.element); - this.scrollToLastComment(); - return; - } - } - - // Position and show - we need to reposition every time since - // the DOM could have changed from zooming - if (!this.isMobile) { - this.position(); - } - - this.scrollToLastComment(); - this.emit('annotationshow'); - } - - /** - * Auto scroll annotations dialog to bottom where new comment was added - * - * @return {void} - */ - scrollToLastComment() { - if (!this.element) { - return; - } - - // Activate and move cursor in the appropriate text area if not in read-only mode - if (this.hasAnnotations) { - this.activateReply(); - } - - const textAreaEl = this.hasAnnotations - ? this.element.querySelector(`.${CLASS_REPLY_TEXTAREA}`) - : this.element.querySelector(constants.SELECTOR_ANNOTATION_TEXTAREA); - util.focusTextArea(textAreaEl); - - const annotationsEl = this.element.querySelector(constants.SELECTOR_ANNOTATION_CONTAINER); - if (annotationsEl) { - const isDialogFlipped = this.dialogEl.classList.contains(CLASS_FLIPPED_DIALOG); - const clientHeight = isDialogFlipped ? 0 : annotationsEl.clientHeight; - annotationsEl.scrollTop = annotationsEl.scrollHeight - clientHeight; - } - } - - /** - * Shows the shared mobile dialog. - * - * @return {void} - */ - showMobileDialog() { - this.element = this.container.querySelector(`.${constants.CLASS_MOBILE_ANNOTATION_DIALOG}`); - - // Do not re-show dialog if it is already visible - if (!this.element.classList.contains(constants.CLASS_HIDDEN)) { - return; - } - - util.showElement(this.element); - this.element.appendChild(this.dialogEl); - - const commentEls = this.element.querySelectorAll(`.${CLASS_COMMENT}`); - if (this.highlightDialogEl && !commentEls.length) { - this.element.classList.add(constants.CLASS_ANNOTATION_PLAIN_HIGHLIGHT); - - const headerEl = this.element.querySelector(constants.SELECTOR_MOBILE_DIALOG_HEADER); - headerEl.classList.add(constants.CLASS_HIDDEN); - } - - this.element.classList.add(constants.CLASS_ANIMATE_DIALOG); - - this.bindDOMListeners(); - } - - /** - * Hides the shared mobile dialog. - * - * @return {void} - */ - hideMobileDialog() { - if (!this.element) { - return; - } - - if (this.dialogEl && this.dialogEl.parentNode) { - this.dialogEl.parentNode.removeChild(this.dialogEl); - } - - // Clear annotations from dialog - util.hideElement(this.element); - this.unbindDOMListeners(); - this.element = util.generateMobileDialogEl(); - } - - /** - * Hides the dialog. - * - * @return {void} - */ - hide() { - if (this.element && this.element.classList.contains(constants.CLASS_HIDDEN)) { - return; - } - - if (this.isMobile) { - this.hideMobileDialog(); - } - - util.hideElement(this.element); - this.deactivateReply(); - this.emit('annotationhide'); - - // Make sure entire thread icon displays for flipped dialogs - this.toggleFlippedThreadEl(); - } - - /** - * Adds an annotation to the dialog. - * - * @param {Annotation} annotation Annotation to add - * @return {void} - */ - addAnnotation(annotation) { - // Show new section if needed - if (!this.hasAnnotations) { - const createSectionEl = this.element.querySelector(constants.SECTION_CREATE); - const showSectionEl = this.element.querySelector(constants.SECTION_SHOW); - util.hideElement(createSectionEl); - util.showElement(showSectionEl); - this.hasAnnotations = true; - } - - this.addAnnotationElement(annotation); - } - - /** - * Removes an annotation from the dialog. - * - * @param {string} annotationID ID of annotation to remove - * @return {void} - */ - removeAnnotation(annotationID) { - const annotationEl = this.element.querySelector(`[data-annotation-id="${annotationID}"]`); - if (annotationEl) { - annotationEl.parentNode.removeChild(annotationEl); - } - - const replyTextEl = this.element.querySelector(`.${CLASS_REPLY_TEXTAREA}`); - if (replyTextEl) { - replyTextEl.focus(); - } - } - - /** - * Posts an annotation in the dialog. - * - * @param {string} [textInput] Annotation text to post - * @return {void} - */ - postAnnotation(textInput) { - const annotationTextEl = this.element.querySelector(constants.SELECTOR_ANNOTATION_TEXTAREA); - const text = textInput || annotationTextEl.value; - if (text.trim() === '') { - annotationTextEl.classList.add(constants.CLASS_INVALID_INPUT); - return; - } - - this.emit('annotationcreate', { text }); - annotationTextEl.value = ''; - } - - //-------------------------------------------------------------------------- - // Abstract - //-------------------------------------------------------------------------- - - /** - * Must be implemented to position the dialog on the preview. - * - * @return {void} - */ - position() {} - - //-------------------------------------------------------------------------- - // Protected - //-------------------------------------------------------------------------- - - /** - * Sets up the dialog element. - * - * @param {Object} [annotations] Annotations to show in the dialog - * @param {HTMLElement} [threadEl] Annotation icon element - * @return {void} - * @protected - */ - setup(annotations = [], threadEl = undefined) { - this.threadEl = threadEl; - - // Generate HTML of dialog - this.dialogEl = this.generateDialogEl(Object.keys(annotations).length); - this.dialogEl.classList.add(constants.CLASS_ANNOTATION_CONTAINER); - - // Setup annotations dialog if not on a mobile device - if (!this.isMobile) { - this.element = document.createElement('div'); - this.element.setAttribute('data-type', constants.DATA_TYPE_ANNOTATION_DIALOG); - this.element.classList.add(constants.CLASS_ANNOTATION_DIALOG); - this.element.classList.add(constants.CLASS_HIDDEN); - this.element.innerHTML = `
`; - this.element.appendChild(this.dialogEl); - - // Adding thread number to dialog - const firstAnnotation = util.getFirstAnnotation(annotations); - if (firstAnnotation) { - this.element.dataset.threadNumber = firstAnnotation.threadNumber; - } - - this.bindDOMListeners(); - } - - // Add annotation elements - this.addSortedAnnotations(annotations); - } - - /** - * Sorts and adds annotations to the dialog - * - * @param {Object} annotations Annotations to show in the dialog - * @return {void} - * @protected - */ - addSortedAnnotations(annotations) { - // Sort annotations by date created - const sorted = Object.keys(annotations).map((key) => annotations[key]); - sorted.sort((a, b) => { - return new Date(a.created) - new Date(b.created); - }); - - // Add sorted annotations to dialog - sorted.forEach((annotation) => { - this.addAnnotationElement(annotation); - }); - } - - /** - * Binds DOM event listeners. - * - * @protected - * @return {void} - */ - bindDOMListeners() { - this.element.addEventListener('keydown', this.keydownHandler); - this.element.addEventListener('wheel', this.stopPropagation); - this.element.addEventListener('mouseup', this.stopPropagation); - - if (this.hasTouch) { - this.element.addEventListener('touchstart', this.clickHandler); - this.element.addEventListener('touchstart', this.stopPropagation); - } - - const replyTextEl = this.element.querySelector(`.${CLASS_REPLY_TEXTAREA}`); - if (replyTextEl) { - replyTextEl.addEventListener('focus', this.validateTextArea); - } - - const annotationTextEl = this.element.querySelector(constants.SELECTOR_ANNOTATION_TEXTAREA); - if (annotationTextEl) { - annotationTextEl.addEventListener('focus', this.validateTextArea); - } - - if (!this.isMobile) { - this.element.addEventListener('click', this.clickHandler); - } - } - - /** - * Removes red border around textarea on focus - * - * @protected - * @param {Event} event Keyboard event - * @return {void} - */ - validateTextArea(event) { - const textEl = event.target; - if (textEl.type !== 'textarea' || textEl.value.trim() === '') { - return; - } - - textEl.classList.remove(constants.CLASS_INVALID_INPUT); - } - - /** - * Unbinds DOM event listeners. - * - * @protected - * @return {void} - */ - unbindDOMListeners() { - this.element.removeEventListener('keydown', this.keydownHandler); - this.element.removeEventListener('mouseup', this.stopPropagation); - this.element.removeEventListener('wheel', this.stopPropagation); - - if (this.hasTouch) { - this.element.removeEventListener('touchstart', this.clickHandler); - this.element.removeEventListener('touchstart', this.stopPropagation); - } - - const replyTextEl = this.element.querySelector(`.${CLASS_REPLY_TEXTAREA}`); - if (replyTextEl) { - replyTextEl.removeEventListener('focus', this.validateTextArea); - } - - const annotationTextEl = this.element.querySelector(constants.SELECTOR_ANNOTATION_TEXTAREA); - if (annotationTextEl) { - annotationTextEl.removeEventListener('focus', this.validateTextArea); - } - - if (!this.isMobile) { - this.element.removeEventListener('click', this.clickHandler); - this.element.removeEventListener('click', this.stopPropagation); - } - } - - /** - * Enable all buttons for the temporary annotation element - * - * @protected - * @param {string} annotationID Annotation of saved annotation element - * @return {void} - */ - enable(annotationID) { - const annotationEl = this.element.querySelector(`[data-annotation-id="${annotationID}"]`); - if (!annotationEl) { - return; - } - - const btns = annotationEl.querySelectorAll('button'); - Array.prototype.forEach.call(btns, (btn) => { - btn.classList.remove(constants.CLASS_DISABLED); - }); - } - - /** - * Disable all buttons for the temporary annotation element - * - * @protected - * @param {string} tempAnnotationID Annotation of temporary annotation element - * @return {void} - */ - disable(tempAnnotationID) { - const annotationEl = this.element.querySelector(`[data-annotation-id="${tempAnnotationID}"]`); - if (!annotationEl) { - return; - } - - const btns = annotationEl.querySelectorAll('button'); - Array.prototype.forEach.call(btns, (btn) => { - btn.classList.add(constants.CLASS_DISABLED); - }); - } - - //-------------------------------------------------------------------------- - // Private - //-------------------------------------------------------------------------- - - /** - * Keydown handler for dialog. - * - * @private - * @param {Event} event DOM event - * @return {void} - */ - keydownHandler(event) { - event.stopPropagation(); - - const key = util.decodeKeydown(event); - if (key === 'Escape') { - if (this.hasAnnotations) { - this.hide(); - } else { - this.cancelAnnotation(); - } - } else { - const dataType = util.findClosestDataType(event.target); - if (dataType === CLASS_REPLY_TEXTAREA) { - this.scrollToLastComment(); - } - } - } - - /** - * Stops propagation of DOM event. - * - * @private - * @param {Event} event DOM event - * @return {void} - */ - stopPropagation(event) { - event.stopPropagation(); - } - - /** - * Click handler on dialog. - * - * @private - * @param {Event} event DOM event - * @return {void} - */ - clickHandler(event) { - event.stopPropagation(); - - // NOTE: This is a workaround when buttons are not given precedence in the event chain - if (this.isMobile && event.target && event.target.nodeName === 'BUTTON') { - event.preventDefault(); - } - - const eventTarget = event.target; - const dataType = util.findClosestDataType(eventTarget); - const annotationID = util.findClosestDataType(eventTarget, 'data-annotation-id'); - - switch (dataType) { - // Clicking 'Post' button to create an annotation - case constants.DATA_TYPE_POST: - this.postAnnotation(); - break; - // Clicking 'Cancel' button to cancel the annotation OR - // Clicking 'X' button on mobile dialog to close - case constants.DATA_TYPE_CANCEL: - case constants.DATA_TYPE_MOBILE_CLOSE: - // @spramod: is the mobile close button still needed? - this.hide(); - - if (!this.isMobile) { - // Cancels + destroys the annotation thread - this.cancelAnnotation(); - } - break; - // Clicking inside reply text area - case constants.DATA_TYPE_REPLY_TEXTAREA: - this.activateReply(); - break; - // Canceling a reply - case constants.DATA_TYPE_CANCEL_REPLY: - this.deactivateReply(true); - break; - // Clicking 'Post' button to create a reply annotation - case constants.DATA_TYPE_POST_REPLY: - this.postReply(); - break; - // Clicking trash icon to initiate deletion - case constants.DATA_TYPE_DELETE: - this.showDeleteConfirmation(annotationID); - break; - // Clicking 'Cancel' button to cancel deletion - case constants.DATA_TYPE_CANCEL_DELETE: - this.hideDeleteConfirmation(annotationID); - break; - // Clicking 'Delete' button to confirm deletion - case constants.DATA_TYPE_CONFIRM_DELETE: - this.deleteAnnotation(annotationID); - break; - - default: - break; - } - } - - /** - * Adds an annotation to the dialog. - * - * @private - * @param {Annotation} annotation Annotation to add - * @return {void} - */ - addAnnotationElement(annotation) { - const userId = util.htmlEscape(annotation.user.id || '0'); - - // Temporary until annotation user API is available - let userName; - if (userId === '0') { - userName = this.localized.posting; - } else { - userName = util.htmlEscape(annotation.user.name) || this.localized.anonymousUserName; - } - - const avatarUrl = util.htmlEscape(annotation.user.avatarUrl || ''); - const avatarHtml = util.getAvatarHtml(avatarUrl, userId, userName, this.localized.profileAlt); - const created = new Date(annotation.created).toLocaleString(this.locale, { - month: '2-digit', - day: '2-digit', - year: 'numeric', - hour: '2-digit', - minute: '2-digit' - }); - const textEl = util.createCommentTextNode(annotation.text); - - const annotationEl = document.createElement('div'); - annotationEl.classList.add(CLASS_COMMENT); - annotationEl.setAttribute('data-annotation-id', annotation.annotationID); - - const annotationContainerEl = this.dialogEl.querySelector(`.${CLASS_COMMENTS_CONTAINER}`); - annotationContainerEl.appendChild(annotationEl); - - // Avatar - const avatarEl = document.createElement('div'); - avatarEl.classList.add(constants.CLASS_PROFILE_IMG_CONTAINER); - avatarEl.innerHTML = avatarHtml; - annotationEl.appendChild(avatarEl); - - // Creator namate & date - const profileContainerEl = document.createElement('div'); - profileContainerEl.classList.add(constants.CLASS_PROFILE_CONTAINER); - annotationEl.appendChild(profileContainerEl); - - const userNameEl = document.createElement('div'); - userNameEl.classList.add(constants.CLASS_USER_NAME); - userNameEl.textContent = userName; - profileContainerEl.appendChild(userNameEl); - - const createdEl = document.createElement('div'); - createdEl.classList.add(constants.CLASS_COMMENT_DATE); - createdEl.textContent = created; - profileContainerEl.appendChild(createdEl); - - // Comment - const commentTextEl = document.createElement('div'); - commentTextEl.appendChild(textEl); - annotationEl.appendChild(commentTextEl); - - // Delete button - if (!annotation.permissions.can_delete) { - return; - } - - const deleteBtn = util.generateBtn( - [constants.CLASS_BUTTON_PLAIN, CLASS_BUTTON_DELETE_COMMENT], - this.localized.deleteButton, - ICON_DELETE, - constants.DATA_TYPE_DELETE - ); - annotationEl.appendChild(deleteBtn); - - const deleteConfirmEl = document.createElement('div'); - deleteConfirmEl.classList.add(CLASS_DELETE_CONFIRMATION); - deleteConfirmEl.classList.add(constants.CLASS_HIDDEN); - annotationEl.appendChild(deleteConfirmEl); - - const confirmMsgEl = document.createElement('div'); - confirmMsgEl.classList.add(constants.CLASS_DELETE_CONFIRM_MESSAGE); - confirmMsgEl.textContent = this.localized.deleteConfirmation; - deleteConfirmEl.appendChild(confirmMsgEl); - - const deleteBtnsEl = document.createElement('div'); - deleteBtnsEl.classList.add(constants.CLASS_BUTTON_CONTAINER); - deleteConfirmEl.appendChild(deleteBtnsEl); - - const cancelDeleteBtn = util.generateBtn( - [constants.CLASS_BUTTON, CLASS_CANCEL_DELETE], - this.localized.cancelButton, - this.localized.cancelButton, - constants.DATA_TYPE_CANCEL_DELETE - ); - deleteBtnsEl.appendChild(cancelDeleteBtn); - - const confirmDeleteBtn = util.generateBtn( - [constants.CLASS_BUTTON, CLASS_BUTTON_DELETE_CONFIRM, constants.CLASS_BUTTON_PRIMARY], - this.localized.deleteButton, - this.localized.deleteButton, - constants.DATA_TYPE_CONFIRM_DELETE - ); - deleteBtnsEl.appendChild(confirmDeleteBtn); - } - - /** - * Cancels posting an annotation. - * - * @private - * @return {void} - */ - cancelAnnotation() { - this.emit('annotationcancel'); - } - - /** - * Activates reply textarea. - * - * @private - * @return {void} - */ - activateReply() { - if (!this.dialogEl) { - return; - } - - const replyTextEl = this.dialogEl.querySelector(`.${CLASS_REPLY_TEXTAREA}`); - if (!replyTextEl) { - return; - } - - // Don't activate if reply textarea is already active - const isActive = replyTextEl.classList.contains(constants.CLASS_ACTIVE); - replyTextEl.classList.remove(constants.CLASS_INVALID_INPUT); - if (isActive) { - return; - } - - const replyButtonEls = replyTextEl.parentNode.querySelector(constants.SELECTOR_BUTTON_CONTAINER); - replyTextEl.classList.add(constants.CLASS_ACTIVE); - util.showElement(replyButtonEls); - } - - /** - * Deactivate reply textarea. - * - * @private - * @param {boolean} clearText Whether or not text in text area should be cleared - * @return {void} - */ - deactivateReply(clearText) { - if (!this.dialogEl) { - return; - } - - const replyContainerEl = this.dialogEl.querySelector(`.${CLASS_REPLY_CONTAINER}`); - if (!replyContainerEl) { - return; - } - - const replyTextEl = replyContainerEl.querySelector(`.${CLASS_REPLY_TEXTAREA}`); - const replyButtonEls = replyContainerEl.querySelector(constants.SELECTOR_BUTTON_CONTAINER); - util.resetTextarea(replyTextEl, clearText); - util.hideElement(replyButtonEls); - } - - /** - * Posts a reply in the dialog. - * - * @private - * @return {void} - */ - postReply() { - const replyTextEl = this.element.querySelector(`.${CLASS_REPLY_TEXTAREA}`); - const text = replyTextEl.value; - if (text.trim() === '') { - replyTextEl.classList.add(constants.CLASS_INVALID_INPUT); - return; - } - - this.emit('annotationcreate', { text }); - replyTextEl.value = ''; - replyTextEl.focus(); - } - - /** - * Shows delete confirmation. - * - * @private - * @param {string} annotationID ID of annotation to delete - * @return {void} - */ - showDeleteConfirmation(annotationID) { - const annotationEl = this.element.querySelector(`[data-annotation-id="${annotationID}"]`); - const deleteConfirmationEl = annotationEl.querySelector(`.${CLASS_DELETE_CONFIRMATION}`); - const cancelDeleteButtonEl = annotationEl.querySelector(`.${CLASS_CANCEL_DELETE}`); - const deleteButtonEl = annotationEl.querySelector(constants.SELECTOR_DELETE_COMMENT_BTN); - util.hideElement(deleteButtonEl); - util.showElement(deleteConfirmationEl); - cancelDeleteButtonEl.focus(); - } - - /** - * Hides delete confirmation. - * - * @private - * @param {string} annotationID ID of annotation to delete - * @return {void} - */ - hideDeleteConfirmation(annotationID) { - const annotationEl = this.element.querySelector(`[data-annotation-id="${annotationID}"]`); - const deleteConfirmationEl = annotationEl.querySelector(`.${CLASS_DELETE_CONFIRMATION}`); - const deleteButtonEl = annotationEl.querySelector(constants.SELECTOR_DELETE_COMMENT_BTN); - util.showElement(deleteButtonEl); - util.hideElement(deleteConfirmationEl); - deleteButtonEl.focus(); - } - - /** - * Broadcasts message to delete an annotation. - * - * @private - * @param {string} annotationID ID of annotation to delete - * @return {void} - */ - deleteAnnotation(annotationID) { - this.emit('annotationdelete', { annotationID }); - } - - /** - * Generates the annotation dialog DOM element - * - * @private - * @param {number} numAnnotations length of annotations array - * @return {HTMLElement} Annotation dialog DOM element - */ - generateDialogEl(numAnnotations) { - const dialogEl = document.createElement('div'); - - // Create Section including the create comment box - if (this.canAnnotate) { - const createSectionEl = document.createElement('section'); - createSectionEl.setAttribute('data-section', 'create'); - if (numAnnotations) { - createSectionEl.classList.add(constants.CLASS_HIDDEN); - } - dialogEl.appendChild(createSectionEl); - - const createTextArea = document.createElement('textarea'); - createTextArea.classList.add(constants.CLASS_TEXTAREA); - createTextArea.classList.add(constants.CLASS_ANNOTATION_TEXTAREA); - createTextArea.placeholder = this.localized.addCommentPlaceholder; - createSectionEl.appendChild(createTextArea); - - const createBtnsContainer = document.createElement('div'); - createBtnsContainer.classList.add(constants.CLASS_BUTTON_CONTAINER); - createSectionEl.appendChild(createBtnsContainer); - - const cancelBtn = util.generateBtn( - [constants.CLASS_BUTTON, constants.CLASS_ANNOTATION_BUTTON_CANCEL], - this.localized.cancelButton, - this.localized.cancelButton, - constants.DATA_TYPE_CANCEL - ); - createBtnsContainer.appendChild(cancelBtn); - - const postBtn = util.generateBtn( - [constants.CLASS_BUTTON, constants.CLASS_BUTTON_PRIMARY, constants.CLASS_ANNOTATION_BUTTON_POST], - this.localized.postButton, - this.localized.postButton, - constants.DATA_TYPE_POST - ); - createBtnsContainer.appendChild(postBtn); - } - - // Show section including the annotations container - const showSectionEl = document.createElement('section'); - showSectionEl.setAttribute('data-section', 'show'); - if (!numAnnotations) { - showSectionEl.classList.add(constants.CLASS_HIDDEN); - } - dialogEl.appendChild(showSectionEl); - - const showCommentsContainer = document.createElement('div'); - showCommentsContainer.classList.add(CLASS_COMMENTS_CONTAINER); - showSectionEl.appendChild(showCommentsContainer); - - // Reply container including the reply text area and post/cancel buttons - if (this.canAnnotate) { - const replyContainer = document.createElement('div'); - replyContainer.classList.add(CLASS_REPLY_CONTAINER); - showSectionEl.appendChild(replyContainer); - - const replyTextArea = document.createElement('textarea'); - replyTextArea.classList.add(constants.CLASS_TEXTAREA); - replyTextArea.classList.add(constants.CLASS_ANNOTATION_TEXTAREA); - replyTextArea.classList.add(CLASS_REPLY_TEXTAREA); - replyTextArea.placeholder = this.localized.replyPlaceholder; - replyTextArea.setAttribute('data-type', constants.DATA_TYPE_REPLY_TEXTAREA); - replyContainer.appendChild(replyTextArea); - - const replyBtnsContainer = document.createElement('div'); - replyBtnsContainer.classList.add(constants.CLASS_BUTTON_CONTAINER); - replyBtnsContainer.classList.add(constants.CLASS_HIDDEN); - replyContainer.appendChild(replyBtnsContainer); - - const cancelBtn = util.generateBtn( - [constants.CLASS_BUTTON, constants.CLASS_ANNOTATION_BUTTON_CANCEL], - this.localized.cancelButton, - this.localized.cancelButton, - constants.DATA_TYPE_CANCEL_REPLY - ); - replyBtnsContainer.appendChild(cancelBtn); - - const postBtn = util.generateBtn( - [constants.CLASS_BUTTON, constants.CLASS_BUTTON_PRIMARY, constants.CLASS_ANNOTATION_BUTTON_POST], - this.localized.postButton, - this.localized.postButton, - constants.DATA_TYPE_POST_REPLY - ); - replyBtnsContainer.appendChild(postBtn); - } - - return dialogEl; - } - - /** - * Flip the annotations dialog if the dialog would appear in the lower - * half of the viewer - * - * @private - * @param {number} yPos y coordinate for the top of the dialog - * @param {number} containerHeight height of the current annotation - * container/page - * @return {void} - */ - flipDialog(yPos, containerHeight) { - let top = ''; - let bottom = ''; - const iconPadding = POINT_ANNOTATION_ICON_HEIGHT - POINT_ANNOTATION_ICON_DOT_HEIGHT / 2; - const annotationCaretEl = this.element.querySelector(constants.SELECTOR_ANNOTATION_CARET); - - if (yPos <= containerHeight / 2) { - // Keep dialog below the icon if in the top half of the viewport - top = `${yPos - POINT_ANNOTATION_ICON_DOT_HEIGHT}px`; - bottom = ''; - - this.element.classList.remove(CLASS_FLIPPED_DIALOG); - - annotationCaretEl.style.bottom = ''; - } else { - // Flip dialog to above the icon if in the lower half of the viewport - const flippedY = containerHeight - yPos - iconPadding; - top = ''; - bottom = `${flippedY}px`; - - this.element.classList.add(CLASS_FLIPPED_DIALOG); - - // Adjust dialog caret - annotationCaretEl.style.top = ''; - annotationCaretEl.style.bottom = '0px'; - } - - this.fitDialogHeightInPage(); - this.toggleFlippedThreadEl(); - return { top, bottom }; - } - - /** - * Show/hide the top portion of the annotations icon based on if the - * entire dialog is flipped - * - * @private - * @return {void} - */ - toggleFlippedThreadEl() { - if (!this.element || !this.threadEl) { - return; - } - - const isDialogFlipped = this.element.classList.contains(CLASS_FLIPPED_DIALOG); - if (!isDialogFlipped) { - return; - } - - if (this.element.classList.contains(constants.CLASS_HIDDEN)) { - this.threadEl.classList.remove(CLASS_FLIPPED_DIALOG); - } else { - this.threadEl.classList.add(CLASS_FLIPPED_DIALOG); - } - } - - /** - * Set max height for dialog to prevent the dialog from being cut off - * - * @private - * @return {void} - */ - fitDialogHeightInPage() { - const maxHeight = this.container.clientHeight / 2 - constants.PAGE_PADDING_TOP - constants.PAGE_PADDING_BOTTOM; - this.dialogEl.style.maxHeight = `${maxHeight}px`; - - const commentsEl = this.dialogEl.querySelector(`.${constants.CLASS_ANNOTATION_CONTAINER}`); - if (commentsEl) { - commentsEl.style.maxHeight = `${maxHeight}px`; - } - } -} - -export default AnnotationDialog; diff --git a/src/AnnotationService.js b/src/AnnotationService.js deleted file mode 100644 index 107e63206..000000000 --- a/src/AnnotationService.js +++ /dev/null @@ -1,320 +0,0 @@ -import 'whatwg-fetch'; -import EventEmitter from 'events'; -import Annotation from './Annotation'; -import { getHeaders } from './util'; - -class AnnotationService extends EventEmitter { - //-------------------------------------------------------------------------- - // Static - //-------------------------------------------------------------------------- - - /** - * Generates a rfc4122v4-compliant GUID, from - * http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript. - * - * @return {string} UUID for annotation - */ - static generateID() { - /* eslint-disable */ - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => { - var r = (Math.random() * 16) | 0, - v = c == 'x' ? r : (r & 0x3) | 0x8; - return v.toString(16); - }); - /* eslint-enable */ - } - - //-------------------------------------------------------------------------- - // Typedef - //-------------------------------------------------------------------------- - - /** - * The data object for constructing an Annotation Service. - * @typedef {Object} AnnotationServiceData - * @property {string} apiHost API root - * @property {string} fileId File ID - * @property {string} token Access token - * @property {boolean} canAnnotate Can user annotate - */ - - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- - - /** - * [constructor] - * - * @param {AnnotationServiceData} data - Annotation Service data - * @return {AnnotationService} AnnotationService instance - */ - constructor(data) { - super(); - this.api = data.apiHost; - this.fileId = data.fileId; - this.headers = getHeaders({}, data.token); - this.canAnnotate = data.canAnnotate; - this.user = { - id: '0', - name: this.anonymousUserName - }; - - // Explicitly bind listeners - this.createThreadMap = this.createThreadMap.bind(this); - } - - /** - * Create an annotation. - * - * @param {Annotation} annotation - Annotation to save - * @return {Promise} Promise that resolves with created annotation - */ - create(annotation) { - return new Promise((resolve, reject) => { - fetch(`${this.api}/2.0/annotations`, { - method: 'POST', - headers: this.headers, - body: JSON.stringify({ - item: { - type: 'file_version', - id: annotation.fileVersionId - }, - details: { - type: annotation.type, - drawingPaths: annotation.drawingPaths, - location: annotation.location, - threadID: annotation.threadID - }, - message: annotation.text, - thread: annotation.threadNumber - }) - // NOTE: Ensure that threadNumbers are sent to the API as - // thread, else the API created annotation will have an - // incremented threadNumber. This is due to the naming system - // in the annotations API - }) - .then((response) => response.json()) - .then((data) => { - if (data.type !== 'error' && data.id) { - const tempData = data; - tempData.permissions = { - can_edit: true, - can_delete: true - }; - const createdAnnotation = this.createAnnotation(tempData); - - // Set user if not set already - if (this.user.id === '0') { - this.user = createdAnnotation.user; - } - - resolve(createdAnnotation); - } else { - const error = new Error('Could not create annotation'); - reject(error); - this.emit('annotationerror', { - reason: 'create', - error: error.toString() - }); - } - }) - /* istanbul ignore next */ - .catch((error) => { - reject(new Error('Could not create annotation due to invalid or expired token')); - this.emit('annotationerror', { - reason: 'authorization', - error: error.toString() - }); - }); - }); - } - - /** - * Reads annotations from file version ID. - * - * @param {string} fileVersionId - File version ID to fetch annotations for - * @return {Promise} Promise that resolves with fetched annotations - */ - read(fileVersionId) { - this.annotations = {}; - let resolve; - let reject; - const promise = new Promise((success, failure) => { - resolve = success; - reject = failure; - }); - - this.readFromMarker(resolve, reject, fileVersionId); - return promise; - } - - /** - * Delete an annotation. - * - * @param {string} annotationID - Id of annotation to delete - * @return {Promise} Promise to delete annotation - */ - delete(annotationID) { - return new Promise((resolve, reject) => { - fetch(`${this.api}/2.0/annotations/${annotationID}`, { - method: 'DELETE', - headers: this.headers - }) - .then((response) => { - if (response.status === 204) { - resolve(); - } else { - const error = new Error(`Could not delete annotation with ID ${annotationID}`); - reject(error); - this.emit('annotationerror', { - reason: 'delete', - error: error.toString() - }); - } - }) - /* istanbul ignore next */ - .catch((error) => { - reject(new Error('Could not delete annotation due to invalid or expired token')); - this.emit('annotationerror', { - reason: 'authorization', - error: error.toString() - }); - }); - }); - } - - /** - * Gets a map of thread ID to annotations in that thread. - * - * @param {string} fileVersionId - File version ID to fetch annotations for - * @return {Promise} Promise that resolves with thread map - */ - getThreadMap(fileVersionId) { - return this.read(fileVersionId).then(this.createThreadMap); - } - - //-------------------------------------------------------------------------- - // Private - //-------------------------------------------------------------------------- - - /** - * Generates a map of thread ID to annotations in thread. - * - * @private - * @param {Object} annotations - Annotations to generate map from - * @return {Object} Map of thread ID to annotations in that thread - */ - createThreadMap(annotations) { - const threadMap = {}; - this.annotations = annotations; - - // Construct map of thread ID to annotations - Object.keys(annotations).forEach((annotationID) => { - const annotation = annotations[annotationID]; - const { threadID } = annotation; - const thread = threadMap[threadID] || []; - threadMap[threadID] = thread; - thread[annotation.annotationID] = annotation; - }); - - return threadMap; - } - - /** - * Generates an Annotation object from an API response. - * - * @private - * @param {Object} data - API response data - * @return {Annotation} Created annotation - */ - createAnnotation(data) { - return new Annotation({ - annotationID: data.id, - fileVersionId: data.item.id, - threadID: data.details.threadID, - type: data.details.type, - threadNumber: data.thread, - text: data.message, - location: data.details.location, - user: { - id: data.created_by.id, - name: data.created_by.name, - avatarUrl: data.created_by.profile_image - }, - permissions: data.permissions, - created: data.created_at, - modified: data.modified_at - }); - } - - /** - * Construct the URL to read annotations with a marker or limit added - * - * @private - * @param {string} fileVersionId - File version ID to fetch annotations for - * @param {string} marker - Marker to use if there are more than limit annotations - * @param {int} limit - The amout of annotations the API will return per call - * @return {Promise} Promise that resolves with fetched annotations - */ - getReadUrl(fileVersionId, marker = null, limit = null) { - let apiUrl = `${this.api}/2.0/files/${this.fileId}/annotations?version=${ - fileVersionId - }&fields=item,thread,details,message,created_by,created_at,modified_at,permissions`; - if (marker) { - apiUrl += `&marker=${marker}`; - } - - if (limit) { - apiUrl += `&limit=${limit}`; - } - - return apiUrl; - } - - /** - * Reads annotations from file version ID starting at a marker. The default - * limit is 100 annotations per API call. - * - * @private - * @param {Function} resolve - Promise resolution handler - * @param {Function} reject - Promise rejection handler - * @param {string} fileVersionId - File version ID to fetch annotations for - * @param {string} marker - Marker to use if there are more than limit annotations - * @param {int} limit - The amout of annotations the API will return per call - * @return {void} - */ - readFromMarker(resolve, reject, fileVersionId, marker = null, limit = null) { - fetch(this.getReadUrl(fileVersionId, marker, limit), { - headers: this.headers - }) - .then((response) => response.json()) - .then((data) => { - if (data.type === 'error' || !Array.isArray(data.entries)) { - const error = new Error(`Could not read annotations from file version with ID ${fileVersionId}`); - reject(error); - this.emit('annotationerror', { - reason: 'read', - error: error.toString() - }); - } else { - data.entries.forEach((annotationData) => { - const annotation = this.createAnnotation(annotationData); - this.annotations[annotation.annotationID] = annotation; - }); - - if (data.next_marker) { - this.readFromMarker(resolve, reject, fileVersionId, data.next_marker, limit); - } else { - resolve(this.annotations); - } - } - }) - .catch((error) => { - reject(new Error('Could not read annotations from file due to invalid or expired token')); - this.emit('annotationerror', { - reason: 'authorization', - error: error.toString() - }); - }); - } -} -export default AnnotationService; diff --git a/src/AnnotationThread.js b/src/AnnotationThread.js index 060509ebb..90d4ef50d 100644 --- a/src/AnnotationThread.js +++ b/src/AnnotationThread.js @@ -1,69 +1,103 @@ +// @flow import EventEmitter from 'events'; -import Annotation from './Annotation'; -import AnnotationService from './AnnotationService'; +import React from 'react'; +import { render, unmountComponentAtNode } from 'react-dom'; + +import AnnotationAPI from './api/AnnotationAPI'; import * as util from './util'; import { ICON_PLACED_ANNOTATION } from './icons/icons'; import { - STATES, - TYPES, CLASS_ANNOTATION_POINT_MARKER, + CLASS_FLIPPED_POPOVER, DATA_TYPE_ANNOTATION_INDICATOR, + STATES, THREAD_EVENT, - CLASS_HIDDEN + TYPES } from './constants'; +import AnnotationPopover from './components/AnnotationPopover'; class AnnotationThread extends EventEmitter { - //-------------------------------------------------------------------------- - // Typedef - //-------------------------------------------------------------------------- - - /** - * The data object for constructing a thread. - * @typedef {Object} AnnotationThreadData - * @property {HTMLElement} annotatedElement HTML element being annotated on - * @property {Object} [annotations] Annotations in thread - none if - * this is a new thread - * @property {AnnotationService} annotationService Annotations CRUD service - * @property {string} fileVersionId File version ID - * @property {Object} location Location object - * @property {string} threadID Thread ID - * @property {string} thread Thread number - * @property {string} type Type of thread - */ - - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- + /** @param {HTMLElement} */ + annotatedElement: HTMLElement; + + /** @param {Object} */ + annotations: Object; + + /** @param {AnnotationAPI} */ + api: AnnotationAPI; + + /** @param {string} */ + fileVersionId: string; + + /** @param {Location} */ + location: Location; + + /** @param {string} */ + threadID: ?string; + + /** @param {string} */ + threadNumber: string; + + /** @param {AnnotationType} */ + type: AnnotationType; + + /** @param {boolean} */ + canComment: boolean; /** * [constructor] * - * @param {AnnotationThreadData} data - Data for constructing thread + * @param {Object} data - Data for constructing thread * @return {AnnotationThread} Annotation thread instance */ - constructor(data) { + constructor(data: Object) { super(); this.annotatedElement = data.annotatedElement; - this.annotations = data.annotations || {}; - this.annotationService = data.annotationService; + this.api = data.api; this.container = data.container; this.fileVersionId = data.fileVersionId; this.location = data.location; - this.threadID = data.threadID || AnnotationService.generateID(); + this.threadID = data.threadID || AnnotationAPI.generateID(); this.threadNumber = data.threadNumber || ''; this.type = data.type; this.locale = data.locale; - this.isMobile = data.isMobile || false; this.hasTouch = data.hasTouch || false; this.permissions = data.permissions; - this.localized = data.localized; this.state = STATES.inactive; + this.canComment = true; + this.headerHeight = data.headerHeight; - this.regenerateBoundary(); + this.id = data.id; + this.type = data.type; + this.location = data.location; + this.threadNumber = data.threadNumber; + this.createdAt = data.createdAt; + this.createdBy = data.createdBy; + this.modifiedAt = data.modifiedAt; + this.fileVersionId = data.fileVersionId; + this.threadID = data.threadID || AnnotationAPI.generateID(); + this.canDelete = data.canDelete; + this.canAnnotate = data.canAnnotate; + this.canComment = true; + this.comments = data.comments + ? data.comments.sort((a, b) => new Date(a.createdAt) - new Date(b.createdAt)) + : []; + + // $FlowFixMe + this.renderAnnotationPopover = this.renderAnnotationPopover.bind(this); + // $FlowFixMe + this.handleBlur = this.handleBlur.bind(this); + // $FlowFixMe + this.onCommentClick = this.onCommentClick.bind(this); + // $FlowFixMe + this.save = this.save.bind(this); + // $FlowFixMe + this.updateTemporaryAnnotation = this.updateTemporaryAnnotation.bind(this); + // $FlowFixMe + this.delete = this.delete.bind(this); - // Explicitly bind listeners - this.showDialog = this.showDialog.bind(this); + this.regenerateBoundary(); this.setup(); } @@ -74,11 +108,8 @@ class AnnotationThread extends EventEmitter { * @return {void} */ destroy() { - if (this.dialog && !this.isMobile) { - this.unbindCustomListenersOnDialog(); - this.dialog.destroy(); - this.dialog = null; - } + this.threadID = null; + this.unmountPopover(); if (this.element) { this.unbindDOMListeners(); @@ -101,7 +132,8 @@ class AnnotationThread extends EventEmitter { * @return {void} */ hide() { - util.hideElement(this.element); + this.state = STATES.inactive; + this.unmountPopover(); } /** @@ -114,93 +146,165 @@ class AnnotationThread extends EventEmitter { } /** - * Whether or not thread dialog is visible - * + * Positions the annotation popover + * * @return {void} */ - isDialogVisible() { - return !!(this.dialog && this.dialog.element && !this.dialog.element.classList.contains(CLASS_HIDDEN)); + position = () => { + /* eslint-enable no-unused-vars */ + throw new Error('Implement me!'); + }; + + /** + * Returns the parent element for the annotation popover + * + * @return {HTMLElement} Parent element for the annotation popover + */ + getPopoverParent() { + return util.shouldDisplayMobileUI(this.container) + ? this.container + : util.getPageEl(this.annotatedElement, this.location.page); } /** * Shows the appropriate annotation dialog for this thread. * + * @param {Event} event - Mouse event * @return {void} */ - showDialog() { - // Prevents the annotations dialog from being set up on every call - if (!this.dialog.element) { - this.dialog.setup(this.annotations, this.element); + renderAnnotationPopover(event: Event = null) { + if (event) { + event.stopPropagation(); + event.preventDefault(); } - this.dialog.show(); + const isPending = this.state === STATES.pending; + + const pageEl = this.getPopoverParent(); + this.popoverComponent = render( + , + util.getPopoverLayer(pageEl) + ); } /** - * Hides the appropriate annotation dialog for this thread. + * Resets and unmounts the annotation popover * * @return {void} */ - hideDialog() { - if (this.dialog) { - this.state = STATES.inactive; - this.dialog.hide(); + unmountPopover() { + this.reset(); + + this.toggleFlippedThreadEl(); + + const pageEl = this.getPopoverParent(); + const popoverLayer = pageEl.querySelector('.ba-dialog-layer'); + if (this.popoverComponent && popoverLayer) { + unmountComponentAtNode(popoverLayer); + this.popoverComponent = null; } } /** * Saves an annotation. * - * @param {string} type - Type of annotation - * @param {string} text - Text of annotation to save + * @param {AnnotationType} type - Type of annotation + * @param {string} message - Text of annotation to save * @return {Promise} - Annotation create promise */ - saveAnnotation(type, text) { - const annotationData = this.createAnnotationData(type, text); + save(type: AnnotationType, message: string): Promise { + const annotationData = this.createAnnotationData(type, message); // Save annotation on client - const tempAnnotationID = AnnotationService.generateID(); - const tempAnnotationData = annotationData; - tempAnnotationData.annotationID = tempAnnotationID; - tempAnnotationData.permissions = { - can_edit: true, - can_delete: true - }; - tempAnnotationData.created = new Date().getTime(); - tempAnnotationData.modified = tempAnnotationData.created; - const tempAnnotation = new Annotation(tempAnnotationData); - this.saveAnnotationToThread(tempAnnotation); - this.state = STATES.inactive; + const id = AnnotationAPI.generateID(); + this.updateAnnotationThread({ + id, + message, + permissions: { + can_edit: true, + can_delete: true + }, + createdBy: this.api.user, + createdAt: new Date().toLocaleString() + }); - if (this.dialog) { - this.dialog.disable(tempAnnotation.annotationID); - } + this.state = STATES.inactive; + this.renderAnnotationPopover(); // Save annotation on server - return this.annotationService + return this.api + // $FlowFixMe .create(annotationData) - .then((savedAnnotation) => this.updateTemporaryAnnotation(tempAnnotation, savedAnnotation)) - .catch((error) => this.handleThreadSaveError(error, tempAnnotationID)); + .then((savedAnnotation) => this.updateTemporaryAnnotation(id, savedAnnotation)) + .catch((error) => this.handleThreadSaveError(error, id)); + } + + /** + * Update the annotation thread instance with annotation data/comments + * + * @param {Object} data - Annotation data + * @return {void} + */ + updateAnnotationThread(data: Object) { + if (!this.threadNumber) { + this.id = data.id; + this.threadNumber = data.threadNumber; + this.threadID = data.threadID; + } + + // If annotation is the first in the thread + const { message } = data; + if (message && message.trim() !== '') { + this.comments.push(data); + } else { + this.createdAt = data.createdAt; + this.createdBy = data.createdBy; + this.modifiedAt = data.modifiedAt; + } } + /** + * Does nothing by default + * + * @return {void} + */ + onCommentClick() {} + /** * Deletes an annotation. * - * @param {string} annotationID - ID of annotation to delete + * @param {Object} annotationToRemove - annotation to delete * @param {boolean} [useServer] - Whether or not to delete on server, default true * @return {Promise} - Annotation delete promise */ - deleteAnnotation(annotationID, useServer = true) { + delete(annotationToRemove: Object, useServer: boolean = true): Promise { // Ignore if no corresponding annotation exists in thread or user doesn't have permissions - const annotation = this.annotations[annotationID]; + const { id: annotationIDToRemove } = annotationToRemove; + const annotation = + annotationIDToRemove !== this.id ? this.comments.find(({ id }) => id === annotationIDToRemove) : this; if (!annotation) { // Broadcast error this.emit(THREAD_EVENT.deleteError); /* eslint-disable no-console */ - console.error( - THREAD_EVENT.deleteError, - `Annotation with ID ${annotation.annotationID} could not be found.` - ); + console.error(THREAD_EVENT.deleteError, `Annotation with ID ${annotationIDToRemove} could not be found.`); /* eslint-enable no-console */ return Promise.reject(); } @@ -211,37 +315,13 @@ class AnnotationThread extends EventEmitter { /* eslint-disable no-console */ console.error( THREAD_EVENT.deleteError, - `User does not have the correct permissions to delete annotation with ID ${annotation.annotationID}.` + `User does not have the correct permissions to delete annotation with ID ${annotation.id}.` ); /* eslint-enable no-console */ return Promise.reject(); } - // Delete annotation on client - delete this.annotations[annotationID]; - - // If the user doesn't have permission to delete the entire highlight - // annotation, display the annotation as a plain highlight - let firstAnnotation = util.getFirstAnnotation(this.annotations); - let canDeleteAnnotation = - firstAnnotation && firstAnnotation.permissions && firstAnnotation.permissions.can_delete; - if (util.isPlainHighlight(this.annotations) && !canDeleteAnnotation) { - this.cancelFirstComment(); - - // If this annotation was the last one in the thread, destroy the thread - } else if (!firstAnnotation || util.isPlainHighlight(this.annotations)) { - if (this.isMobile && this.dialog) { - this.dialog.hideMobileDialog(); - this.dialog.removeAnnotation(annotationID); - } - this.destroy(); - - // Otherwise, remove deleted annotation from dialog - } else if (this.dialog) { - this.dialog.removeAnnotation(annotationID); - this.showDialog(); - this.dialog.activateReply(); - } + this.cleanupAnnotationOnDelete(annotationIDToRemove); if (!useServer) { /* eslint-disable no-console */ @@ -254,87 +334,81 @@ class AnnotationThread extends EventEmitter { } // Delete annotation on server - return this.annotationService - .delete(annotationID) - .then(() => { - // Ensures that blank highlight comment is also deleted when removing - // the last comment on a highlight - firstAnnotation = util.getFirstAnnotation(this.annotations); - canDeleteAnnotation = - firstAnnotation && firstAnnotation.permissions && firstAnnotation.permissions.can_delete; - if (util.isPlainHighlight(this.annotations) && canDeleteAnnotation) { - this.annotationService.delete(firstAnnotation.annotationID); - } - - // Broadcast thread cleanup if needed - firstAnnotation = util.getFirstAnnotation(this.annotations); - if (!firstAnnotation) { - this.emit(THREAD_EVENT.threadCleanup); - } - - // Broadcast annotation deletion event - this.emit(THREAD_EVENT.delete); - }) - .catch((error) => { - // Broadcast error - this.emit(THREAD_EVENT.deleteError); - /* eslint-disable no-console */ - console.error(THREAD_EVENT.deleteError, error.toString()); - /* eslint-enable no-console */ - }); + return this.api + .delete(annotationIDToRemove) + .then(this.deleteSuccessHandler) + .catch(this.deleteErrorHandler); } - //-------------------------------------------------------------------------- - // Abstract - //-------------------------------------------------------------------------- + /** + * Appropriately cleanup the AnnotationThread instance based on the delete action + * + * @param {string} annotationIDToRemove Annotation ID to remove + * @return {void} + */ + cleanupAnnotationOnDelete(annotationIDToRemove: string) { + // Delete matching comment from annotation + this.comments = this.comments.filter(({ id }) => id !== annotationIDToRemove); + + if (this.canDelete && this.comments.length <= 0) { + // If this annotation was the last one in the thread, destroy the thread + this.destroy(); + this.threadID = null; + } else { + // Otherwise, display annotation with deleted comment + this.renderAnnotationPopover(); + } + } /** - * Cancels the first comment on the thread + * Handles the successful delete of an annotation or one of it's comments * * @return {void} */ - cancelFirstComment() {} + deleteSuccessHandler = () => { + // Broadcast annotation deletion event + this.emit(THREAD_EVENT.delete); + }; /** - * Must be implemented to show the annotation indicator. + * Handles annotation delete errors * + * @param {Error} error Delete error * @return {void} */ - show() {} + deleteErrorHandler(error: Error) { + // Broadcast error + this.emit(THREAD_EVENT.deleteError); + /* eslint-disable no-console */ + console.error(THREAD_EVENT.deleteError, error.toString()); + /* eslint-enable no-console */ + } /** - * Must be implemented to create the appropriate annotation dialog and save - * as a property on the thread. + * Cancels the first comment on the thread * * @return {void} */ - createDialog() {} + cancelFirstComment() {} - //-------------------------------------------------------------------------- - // Protected - //-------------------------------------------------------------------------- + /** + * Must be implemented to show the annotation indicator. + * + * @return {void} + */ + show() {} /** * Sets up the thread. Creates HTML for annotation indicator, sets * appropriate dialog, and binds event listeners. * - * @protected * @return {void} */ setup() { - const firstAnnotation = util.getFirstAnnotation(this.annotations); - if (!firstAnnotation) { - this.state = STATES.pending; - } else { + if (this.threadNumber) { this.state = STATES.inactive; - } - - this.createDialog(); - this.bindCustomListenersOnDialog(); - - if (this.dialog) { - this.dialog.isMobile = this.isMobile; - this.dialog.localized = this.localized; + } else { + this.state = STATES.pending; } this.setupElement(); @@ -343,7 +417,6 @@ class AnnotationThread extends EventEmitter { /** * Sets up indicator element. * - * @protected * @return {void} */ setupElement() { @@ -354,7 +427,6 @@ class AnnotationThread extends EventEmitter { /** * Binds DOM event listeners for the thread. * - * @protected * @return {void} */ bindDOMListeners() { @@ -362,13 +434,13 @@ class AnnotationThread extends EventEmitter { return; } - this.element.addEventListener('click', this.showDialog); + this.element.addEventListener('click', this.renderAnnotationPopover); + this.element.addEventListener('blur', this.handleBlur); } /** * Unbinds DOM event listeners for the thread. * - * @protected * @return {void} */ unbindDOMListeners() { @@ -376,79 +448,41 @@ class AnnotationThread extends EventEmitter { return; } - this.element.removeEventListener('click', this.showDialog); + this.element.removeEventListener('click', this.renderAnnotationPopover); + this.element.removeEventListener('blur', this.handleBlur); } /** - * Binds custom event listeners for the dialog. + * Called when the annotation element loses focus * - * @protected * @return {void} */ - bindCustomListenersOnDialog() { - if (!this.dialog) { - return; - } - - // Explicitly bind listeners to the dialog - this.createAnnotation = this.createAnnotation.bind(this); - this.cancelUnsavedAnnotation = this.cancelUnsavedAnnotation.bind(this); - this.deleteAnnotationWithID = this.deleteAnnotationWithID.bind(this); - - this.dialog.addListener('annotationcreate', this.createAnnotation); - this.dialog.addListener('annotationcancel', this.cancelUnsavedAnnotation); - this.dialog.addListener('annotationdelete', this.deleteAnnotationWithID); - this.dialog.addListener('annotationshow', () => this.emit(THREAD_EVENT.show)); - this.dialog.addListener('annotationhide', () => this.emit(THREAD_EVENT.hide)); - } - - /** - * Unbinds custom event listeners for the dialog. - * - * @protected - * @return {void} - */ - unbindCustomListenersOnDialog() { - if (!this.dialog) { - return; - } - - this.dialog.removeAllListeners([ - 'annotationcreate', - 'annotationcancel', - 'annotationdelete', - 'annotationshow', - 'annotationhide' - ]); + handleBlur() { + this.toggleFlippedThreadEl(); } /** * Destroys mobile and pending/pending-active annotation threads * - * @protected * @return {void} */ - cancelUnsavedAnnotation() { - if (!util.isPending(this.state)) { - this.hideDialog(); + cancelUnsavedAnnotation = () => { + if (this.state !== STATES.pending) { + this.unmountPopover(); return; } this.emit(THREAD_EVENT.cancel); this.destroy(); - } - - //-------------------------------------------------------------------------- - // Private - //-------------------------------------------------------------------------- + }; /** * Scroll annotation into the center of the viewport, if possible * - * @private * @return {void} */ scrollIntoView() { + // $FlowFixMe const yPos = parseInt(this.location.y, 10); this.scrollToPage(); this.centerAnnotation(this.annotatedElement.scrollTop + yPos); @@ -457,7 +491,6 @@ class AnnotationThread extends EventEmitter { /** * Scroll to the annotation's page * - * @private * @return {void} */ scrollToPage() { @@ -466,22 +499,22 @@ class AnnotationThread extends EventEmitter { return; } - const pageEl = this.annotatedElement.querySelector(`[data-page-number="${this.location.page}"]`); + const pageEl = this.getPopoverParent(); pageEl.scrollIntoView(); } /** * Adjust page scroll position so annotation is centered in viewport * - * @private * @param {number} scrollVal - scroll value to adjust so annotation is centered in the viewport * @return {void} */ - centerAnnotation(scrollVal) { + centerAnnotation(scrollVal: number) { if (scrollVal < this.annotatedElement.scrollHeight) { this.annotatedElement.scrollTop = scrollVal; } else { + // $FlowFixMe this.annotatedElement.scrollTop = this.annotatedElement.scrollBottom; } } @@ -490,54 +523,35 @@ class AnnotationThread extends EventEmitter { * Update a temporary annotation with the annotation saved on the backend. Set the threadNumber if it has not * yet been set. Propogate the threadnumber to an attached dialog if applicable. * - * @private - * @param {Annotation} tempAnnotation - The locally stored placeholder for the server validated annotation + * @param {string} tempAnnotationID - The locally stored placeholder for the server validated annotation * @param {Annotation} savedAnnotation - The annotation determined by the backend to be used as the source of truth * @return {void} */ - updateTemporaryAnnotation(tempAnnotation, savedAnnotation) { - if (!(tempAnnotation.annotationID in this.annotations)) { - // If no temporary annotation is found, save to thread normally - this.saveAnnotationToThread(savedAnnotation); - } else { - // Otherwise, replace temporary annotation with annotation saved to server - delete this.annotations[tempAnnotation.annotationID]; - this.annotations[savedAnnotation.annotationID] = savedAnnotation; - } - - // Set threadNumber if the savedAnnotation is the first annotation of the thread - if (!this.threadNumber && savedAnnotation && savedAnnotation.threadNumber) { - this.threadNumber = savedAnnotation.threadNumber; + updateTemporaryAnnotation(tempAnnotationID: string, savedAnnotation: Annotation) { + if (this.comments.length > 0) { + this.comments = this.comments.filter(({ id }) => id !== tempAnnotationID); } - if (this.dialog) { - // Add thread number to associated dialog and thread - if (this.dialog.element && this.dialog.element.dataset) { - this.dialog.element.dataset.threadNumber = this.threadNumber; - } + this.updateAnnotationThread(savedAnnotation); - // Remove temporary annotation and replace it with the saved annotation - this.dialog.addAnnotation(savedAnnotation); - this.dialog.removeAnnotation(tempAnnotation.annotationID); - this.dialog.enable(savedAnnotation.annotationID); - this.dialog.scrollToLastComment(); - } - - if (this.isMobile) { + if (util.shouldDisplayMobileUI(this.container)) { // Changing state from pending - this.state = STATES.hover; - this.showDialog(); + this.state = STATES.active; + } else { + this.state = STATES.inactive; } + + this.show(); + this.renderAnnotationPopover(); this.emit(THREAD_EVENT.save); } /** * Creates the HTML for the annotation indicator. * - * @private * @return {HTMLElement} HTML element */ - createElement() { + createElement(): HTMLElement { const indicatorEl = document.createElement('button'); indicatorEl.classList.add(CLASS_ANNOTATION_POINT_MARKER); indicatorEl.setAttribute('data-type', DATA_TYPE_ANNOTATION_INDICATOR); @@ -545,72 +559,46 @@ class AnnotationThread extends EventEmitter { return indicatorEl; } - /** - * Saves the provided annotation to the thread and dialog if appropriate - * and resets state to inactive. - * - * @private - * @param {Annotation} annotation - Annotation to save - * @return {void} - */ - saveAnnotationToThread(annotation) { - this.annotations[annotation.annotationID] = annotation; - - if (this.dialog) { - this.dialog.addAnnotation(annotation); - this.dialog.activateReply(); - } - } - /** * Create an annotation data object to pass to annotation service. * - * @private - * @param {string} type - Type of annotation - * @param {string} text - Annotation text + * @param {AnnotationType} type - Type of annotation + * @param {string} message - Annotation text * @return {Object} Annotation data */ - createAnnotationData(type, text) { + createAnnotationData(type: AnnotationType, message: string) { return { - fileVersionId: this.fileVersionId, - type, - text, - location: this.location, - user: this.annotationService.user, - threadID: this.threadID, - threadNumber: this.threadNumber + item: { + id: this.fileVersionId, + type: 'file_version' + }, + details: { + type, + location: this.location, + threadID: this.threadID + }, + message, + createdBy: this.api.user }; } /** * Creates a new point annotation * - * @private - * @param {Object} data - Annotation data + * @param {string} message - Annotation message string * @return {void} */ - createAnnotation(data) { - this.saveAnnotation(TYPES.point, data.text); - } - - /** - * Deletes annotation with annotationID from thread - * - * @private - * @param {Object} data - Annotation data - * @return {void} - */ - deleteAnnotationWithID(data) { - this.deleteAnnotation(data.annotationID); + createAnnotation(message: string) { + this.save(TYPES.point, message); } /** * Regenerate the coordinates of the rectangular boundary on the saved thread for inserting into the rtree * - * @private * @return {void} */ regenerateBoundary() { + // $FlowFixMe if (!this.location || !this.location.x || !this.location.y) { return; } @@ -624,14 +612,13 @@ class AnnotationThread extends EventEmitter { /** * Deletes the temporary annotation if the annotation failed to save on the server * - * @private * @param {error} error - error thrown while saving the annotation * @param {string} tempAnnotationID - ID of temporary annotation to be updated with annotation from server * @return {void} */ - handleThreadSaveError(error, tempAnnotationID) { + handleThreadSaveError(error: Error, tempAnnotationID: string) { // Remove temporary annotation - this.deleteAnnotation(tempAnnotationID, /* useServer */ false); + this.delete({ id: tempAnnotationID }, /* useServer */ false); // Broadcast error this.emit(THREAD_EVENT.createError); @@ -645,19 +632,22 @@ class AnnotationThread extends EventEmitter { * Generate threadData with relevant information to be emitted with an * annotation thread event * - * @private * @return {Object} threadData - Annotation event thread data */ - getThreadEventData() { + getThreadEventData(): Object { const threadData = { type: this.type, threadID: this.threadID }; - if (this.annotationService.user.id > 0) { - threadData.userId = this.annotationService.user.id; + // $FlowFixMe + if (this.api.user && this.api.user.id > 0) { + // $FlowFixMe + threadData.userId = this.api.user.id; } + if (this.threadNumber) { + // $FlowFixMe threadData.threadNumber = this.threadNumber; } @@ -667,17 +657,54 @@ class AnnotationThread extends EventEmitter { /** * Emits a generic viewer event * - * @private * @emits viewerevent * @param {string} event - Event name * @param {Object} eventData - Event data * @return {void} */ - emit(event, eventData) { + emit(event: Event, eventData: Object) { const threadData = this.getThreadEventData(); super.emit(event, { data: threadData, eventData }); super.emit('threadevent', { event, data: threadData, eventData }); } + + /** + * Keydown handler for dialog. + * + * @param {Event} event DOM event + * @return {void} + */ + keydownHandler(event: Event) { + event.stopPropagation(); + + const key = util.decodeKeydown(event); + if (key === 'Escape') { + if (this.hasAnnotations()) { + this.hide(); + } else { + this.cancelAnnotation(); + } + } + } + + /** + * Show/hide the top portion of the annotations icon based on if the + * entire dialog is flipped + * + * @return {void} + */ + toggleFlippedThreadEl() { + if (!this.element) { + return; + } + + const isDialogFlipped = this.element.classList.contains(CLASS_FLIPPED_POPOVER); + if (!isDialogFlipped) { + return; + } + + this.element.classList.remove(CLASS_FLIPPED_POPOVER); + } } export default AnnotationThread; diff --git a/src/Annotator.js b/src/Annotator.js index 98b79ddb3..fa57628e0 100644 --- a/src/Annotator.js +++ b/src/Annotator.js @@ -1,14 +1,8 @@ +// @flow import EventEmitter from 'events'; -import AnnotationService from './AnnotationService'; import * as util from './util'; import './Annotator.scss'; import { - CLASS_HIDDEN, - DATA_TYPE_ANNOTATION_DIALOG, - CLASS_MOBILE_ANNOTATION_DIALOG, - CLASS_ANNOTATION_DIALOG, - CLASS_MOBILE_DIALOG_HEADER, - ID_MOBILE_ANNOTATION_DIALOG, TYPES, STATES, THREAD_EVENT, @@ -17,23 +11,14 @@ import { CLASS_ANNOTATIONS_LOADED, SELECTOR_BOX_PREVIEW_HEADER_CONTAINER } from './constants'; +import FileVersionAPI from './api/FileVersionAPI'; class Annotator extends EventEmitter { - //-------------------------------------------------------------------------- - // Typedef - //-------------------------------------------------------------------------- + /** @param {HTMLElement} */ + annotatedElement: HTMLElement; - /** - * The data object for constructing an Annotator. - * @typedef {Object} AnnotatorData - * @property {HTMLElement} annotatedElement HTML element to annotate on - * @property {AnnotationService} [annotationService] Annotations CRUD service - * @property {string} fileVersionId File version ID - */ - - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- + /** @param {string} */ + fileVersionId: string; /** * [constructor] @@ -41,13 +26,12 @@ class Annotator extends EventEmitter { * @param {Object} options - Options for constructing an Annotator * @return {Annotator} Annotator instance */ - constructor(options) { + constructor(options: Object) { super(); this.options = options; this.locale = options.location.locale || 'en-US'; this.validationErrorEmitted = false; - this.isMobile = options.isMobile || false; this.hasTouch = options.hasTouch || false; this.localized = options.localizedStrings; @@ -56,11 +40,12 @@ class Annotator extends EventEmitter { this.fileId = file.id; this.permissions = this.getAnnotationPermissions(this.options.file); - this.annotationService = new AnnotationService({ + + this.api = new FileVersionAPI({ apiHost, fileId: this.fileId, token, - canAnnotate: this.permissions.canAnnotate, + permissions: this.permissions, anonymousUserName: this.localized.anonymousUserName }); @@ -71,10 +56,15 @@ class Annotator extends EventEmitter { this.fetchPromise = this.fetchAnnotations(); // Explicitly binding listeners + // $FlowFixMe this.createPointThread = this.createPointThread.bind(this); + // $FlowFixMe this.scaleAnnotations = this.scaleAnnotations.bind(this); + // $FlowFixMe this.handleControllerEvents = this.handleControllerEvents.bind(this); + // $FlowFixMe this.handleServicesErrors = this.handleServicesErrors.bind(this); + // $FlowFixMe this.hideAnnotations = this.hideAnnotations.bind(this); } @@ -90,8 +80,7 @@ class Annotator extends EventEmitter { }); this.unbindDOMListeners(); - this.unbindCustomListenersOnService(); - this.removeListener(ANNOTATOR_EVENT.scale, this.scaleAnnotations); + this.unbindCustomListeners(); } /** @@ -100,7 +89,7 @@ class Annotator extends EventEmitter { * @param {number} [initialScale] - The initial scale factor to render the annotations * @return {void} */ - init(initialScale = 1) { + init(initialScale: number = 1) { // Get the container dom element if selector was passed, in tests this.container = this.options.container; if (typeof this.options.container === 'string') { @@ -119,14 +108,17 @@ class Annotator extends EventEmitter { this.headerElement = this.container.querySelector(SELECTOR_BOX_PREVIEW_HEADER_CONTAINER); } + if (!this.container) { + this.emit(ANNOTATOR_EVENT.loadError, this.localized.loadError); + return; + } + + this.container.classList.add('ba'); + // Get annotated element from container + // $FlowFixMe this.annotatedElement = this.getAnnotatedEl(this.container); - // Set up mobile annotations dialog - if (this.isMobile) { - this.setupMobileDialog(); - } - this.setScale(initialScale); this.setupAnnotations(); this.loadAnnotations(); @@ -136,10 +128,10 @@ class Annotator extends EventEmitter { * Returns whether or not the current annotation mode is enabled for * the current viewer/annotator. * - * @param {string} type - Type of annotation + * @param {AnnotationType} type - Type of annotation * @return {boolean} Whether or not the annotation mode is enabled */ - isModeAnnotatable(type) { + isModeAnnotatable(type: AnnotationType): boolean { if (!this.options.annotator) { return false; } @@ -162,13 +154,11 @@ class Annotator extends EventEmitter { loadAnnotations() { this.fetchPromise .then(() => { - this.generateThreadMap(this.threadMap); + this.generateAnnotationMap(this.annotationMap); this.render(); this.annotatedElement.classList.add(CLASS_ANNOTATIONS_LOADED); }) - .catch((error) => { - this.emit(ANNOTATOR_EVENT.loadError, error); - }); + .catch((error) => this.emit(ANNOTATOR_EVENT.loadError, error)); } /** @@ -177,37 +167,21 @@ class Annotator extends EventEmitter { * @param {number} scale - current zoom scale * @return {void} */ - setScale(scale) { + setScale(scale: number) { + // $FlowFixMe this.annotatedElement.setAttribute('data-scale', scale); } - //-------------------------------------------------------------------------- - // Abstract - //-------------------------------------------------------------------------- - /** * Must be implemented to return an annotation location object from the DOM * event. * * @param {Event} event - DOM event - * @param {string} annotationType - Type of annotation + * @param {AnnotationType} annotationType - Type of annotation * @return {Object} Location object */ /* eslint-disable no-unused-vars */ - getLocationFromEvent(event, annotationType) {} - /* eslint-enable no-unused-vars */ - - /** - * Must be implemented to create the appropriate new thread, add it to the - * in-memory map, and return the thread. - * - * @param {Object} annotations - Annotations in thread - * @param {Object} location - Location object - * @param {string} type - Annotation type - * @return {AnnotationThread} Created annotation thread - */ - /* eslint-disable no-unused-vars */ - createAnnotationThread(annotations, location, type) {} + getLocationFromEvent = (event: Event, annotationType: AnnotationType): ?Location => {}; /* eslint-enable no-unused-vars */ /** @@ -217,31 +191,24 @@ class Annotator extends EventEmitter { * @return {HTMLElement} Annotated element in the viewer */ /* eslint-disable no-unused-vars */ - getAnnotatedEl(containerEl) {} + getAnnotatedEl(containerEl: HTMLElement): ?HTMLElement {} /* eslint-enable no-unused-vars */ - //-------------------------------------------------------------------------- - // Protected - //-------------------------------------------------------------------------- - /** * Annotations setup. * - * @protected * @return {void} */ setupAnnotations() { // Map of page => {threads on page} - this.bindDOMListeners(); - this.bindCustomListenersOnService(this.annotationService); - this.addListener(ANNOTATOR_EVENT.scale, this.scaleAnnotations); this.setupControllers(); + this.bindDOMListeners(); + this.bindCustomListeners(); } /** * Mode controllers setup. * - * @protected * @return {void} */ setupControllers() { @@ -249,8 +216,8 @@ class Annotator extends EventEmitter { const options = { header: this.options.header, - isMobile: this.isMobile, - hasTouch: this.hasTouch + hasTouch: this.hasTouch, + locale: this.locale }; Object.keys(this.modeControllers).forEach((type) => { const controller = this.modeControllers[type]; @@ -261,54 +228,17 @@ class Annotator extends EventEmitter { mode: type, modeButton: this.modeButtons[type], permissions: this.permissions, - annotator: this, localized: this.localized, + fileId: this.fileId, + fileVersionId: this.fileVersionId, + apiHost: this.options.apiHost, + token: this.options.token, + getLocation: this.getLocationFromEvent, options }); controller.addListener('annotationcontrollerevent', this.handleControllerEvents); }); - - const pointController = this.modeControllers[TYPES.point]; - if (pointController && this.isMobile) { - pointController.setupSharedDialog(this.container, { - isMobile: this.isMobile, - hasTouch: this.hasTouch, - localized: this.localized - }); - } - } - - /** - * Sets up the shared mobile dialog element. - * - * @protected - * @return {void} - */ - setupMobileDialog() { - this.mobileDialogEl = util.generateMobileDialogEl(); - this.mobileDialogEl.setAttribute('data-type', DATA_TYPE_ANNOTATION_DIALOG); - this.mobileDialogEl.classList.add(CLASS_MOBILE_ANNOTATION_DIALOG); - this.mobileDialogEl.classList.add(CLASS_ANNOTATION_DIALOG); - this.mobileDialogEl.classList.add(CLASS_HIDDEN); - this.mobileDialogEl.id = ID_MOBILE_ANNOTATION_DIALOG; - this.container.appendChild(this.mobileDialogEl); - } - - /** - * Hides and resets the shared mobile dialog. - * - * @return {void} - */ - removeThreadFromSharedDialog() { - if (!this.mobileDialogEl || this.mobileDialogEl.classList.contains(CLASS_HIDDEN)) { - return; - } - - // Resets the mobile dialog - util.hideElement(this.mobileDialogEl); - util.showElement(`.${CLASS_MOBILE_DIALOG_HEADER}`); - this.mobileDialogEl.removeChild(this.mobileDialogEl.lastChild); } /** @@ -318,16 +248,15 @@ class Annotator extends EventEmitter { * @param {Event} [event] - Mouse event * @return {void} */ - hideAnnotations(event) { - if (event && util.isInDialog(event)) { + hideAnnotations(event: ?Event) { + if (event && util.isInDialog(event, this.container)) { return; } Object.keys(this.modeControllers).forEach((mode) => { + this.modeControllers[mode].destroyPendingThreads(); this.modeControllers[mode].applyActionToThreads((thread) => { - if (!util.isPending(thread.state)) { - thread.hideDialog(); - } + thread.unmountPopover(); }); }); } @@ -336,20 +265,19 @@ class Annotator extends EventEmitter { * Fetches persisted annotations, creates threads as needed, and generates * an in-memory map of page to threads. * - * @protected * @return {Promise} Promise for fetching saved annotations */ - fetchAnnotations() { + fetchAnnotations(): Promise { // Do not load any pre-existing annotations if the user does not have // the correct permissions - if (!this.permissions.canViewAllAnnotations && !this.permissions.canViewOwnAnnotations) { + if (!this.permissions.can_view_annotations_all && !this.permissions.can_view_annotations_self) { return Promise.resolve({}); } - return this.annotationService - .getThreadMap(this.fileVersionId) + return this.api + .fetchVersionAnnotations(this.fileVersionId) .then((threads) => { - this.threadMap = threads; + this.annotationMap = threads; this.emit(ANNOTATOR_EVENT.fetch); }) .catch((err) => { @@ -358,41 +286,27 @@ class Annotator extends EventEmitter { } /** - * Generates a map of thread ID to annotations in thread by page. + * Generates a map of annotations by page. * - * @private - * @param {Object} threadMap - Annotations to generate map from + * @param {Object} annotationMap - Annotations to generate map from * @return {void} */ - generateThreadMap(threadMap) { + generateAnnotationMap(annotationMap: Object) { const { annotator } = this.options; if (!annotator) { return; } - // Generate map of page to threads - Object.keys(threadMap).forEach((threadID) => { - const annotations = threadMap[threadID]; + // Generate map of page to annotations + Object.keys(annotationMap).forEach((id) => { + const annotation = annotationMap[id]; - // NOTE: Using the last annotation to evaluate if the annotation type - // is enabled because highlight comment annotations may have a plain - // highlight as the first annotation in the thread. - const lastAnnotation = util.getLastAnnotation(annotations); - if (!lastAnnotation || !this.isModeAnnotatable(lastAnnotation.type)) { + const controller = this.modeControllers[annotation.type]; + if (!controller) { return; } - // Register a valid annotation thread - // NOTE: The first annotation in the thread is used to determine the - // annotation (which shouldn't change regardless of what is specified - // in later annotations in that specific thread) whereas the last - // annotation is used to determine the type as specified above - const firstAnnotation = util.getFirstAnnotation(annotations); - const thread = this.createAnnotationThread(annotations, firstAnnotation.location, lastAnnotation.type); - const controller = this.modeControllers[lastAnnotation.type]; - if (controller) { - controller.registerThread(thread); - } + controller.registerThread(annotation); }); } @@ -401,7 +315,6 @@ class Annotator extends EventEmitter { * needs to bind event listeners to the DOM in the normal state (ie not * in any annotation mode). * - * @protected * @return {void} */ bindDOMListeners() {} @@ -411,7 +324,6 @@ class Annotator extends EventEmitter { * needs to bind event listeners to the DOM in the normal state (ie not * in any annotation mode). * - * @protected * @return {void} */ unbindDOMListeners() {} @@ -419,74 +331,29 @@ class Annotator extends EventEmitter { /** * Binds custom event listeners for the Annotation Service. * - * @protected * @return {void} */ - bindCustomListenersOnService() { - const service = this.annotationService; - if (!service || !(service instanceof AnnotationService)) { - return; - } - - /* istanbul ignore next */ - service.addListener(ANNOTATOR_EVENT.error, this.handleServicesErrors); + bindCustomListeners() { + this.addListener(ANNOTATOR_EVENT.scale, this.scaleAnnotations); + this.api.addListener(ANNOTATOR_EVENT.error, this.handleServicesErrors); } /** * Unbinds custom event listeners for the Annotation Service. * - * @protected * @return {void} */ - unbindCustomListenersOnService() { - const service = this.annotationService; - if (!service || !(service instanceof AnnotationService)) { - return; - } - service.removeListener(ANNOTATOR_EVENT.error, this.handleServicesErrors); - } - - /** - * Gets thread params for the new annotation thread - * - * @param {Annotation[]} annotations - Annotations in thread - * @param {Object} location - Location object - * @param {string} [type] - Optional annotation type - * @return {AnnotationThread} Created annotation thread - */ - getThreadParams(annotations, location, type) { - const params = { - annotatedElement: this.annotatedElement, - annotations, - annotationService: this.annotationService, - container: this.container, - fileVersionId: this.fileVersionId, - isMobile: this.isMobile, - hasTouch: this.hasTouch, - locale: this.locale, - location, - type, - permissions: this.permissions, - localized: this.localized - }; - - // Set existing thread ID if created with annotations - const firstAnnotation = util.getFirstAnnotation(annotations); - if (firstAnnotation) { - params.threadID = firstAnnotation.threadID; - params.threadNumber = firstAnnotation.threadNumber; - } - - return params; + unbindCustomListeners() { + this.removeListener(ANNOTATOR_EVENT.scale, this.scaleAnnotations); + this.api.removeListener(ANNOTATOR_EVENT.error, this.handleServicesErrors); } /** * Returns the current annotation mode * - * @protected - * @return {string|null} Current annotation mode + * @return {AnnotationType|null} Current annotation mode */ - getCurrentAnnotationMode() { + getCurrentAnnotationMode(): ?AnnotationType { const modes = Object.keys(this.modeControllers).filter((mode) => { const controller = this.modeControllers[mode]; return controller.isEnabled(); @@ -497,7 +364,6 @@ class Annotator extends EventEmitter { /** * Creates a point annotation thread, adds it to in-memory map, and returns it. * - * @private * @param {Object} data - Thread data * @param {string} data.commentText - The text for the first comment in * the thread. @@ -505,7 +371,7 @@ class Annotator extends EventEmitter { * @param {string} data.pendingThreadID - Thread ID for the current pending point thread * @return {AnnotationThread} Created point annotation thread */ - createPointThread(data) { + createPointThread(data: Object): AnnotationThread { // Empty string will be passed in if no text submitted in comment const { commentText, lastPointEvent, pendingThreadID } = data; if (!lastPointEvent || !pendingThreadID || !commentText || commentText.trim() === '') { @@ -523,23 +389,17 @@ class Annotator extends EventEmitter { return null; } - thread.dialog.hasComments = true; - thread.state = STATES.hover; - thread.showDialog(); - thread.dialog.postAnnotation(commentText); + thread.state = STATES.active; + thread.renderAnnotationPopover(); + thread.save(TYPES.point, commentText); this.emit(THREAD_EVENT.threadSave, thread.getThreadEventData()); return thread; } - //-------------------------------------------------------------------------- - // Private - //-------------------------------------------------------------------------- - /** * Renders annotations from memory. * - * @private * @return {void} */ render() { @@ -552,50 +412,55 @@ class Annotator extends EventEmitter { /** * Renders annotations from memory for a specified page. * - * @private * @param {number} pageNum - Page number * @return {void} */ - renderPage(pageNum) { + renderPage(pageNum: number) { Object.keys(this.modeControllers).forEach((mode) => this.modeControllers[mode].renderPage(pageNum)); } /** * Returns annotation permissions * - * @private * @param {Object} file - File - * @return {boolean} Whether or not the annotation mode is enabled + * @return {Object} annotation permissions */ - getAnnotationPermissions(file) { + getAnnotationPermissions(file: Object): BoxItemPermissions { const permissions = file.permissions || {}; + const { + can_annotate = false, + can_view_annotations_all = false, + can_view_annotations_self = false + } = permissions; return { - canAnnotate: permissions.can_annotate || false, - canViewAllAnnotations: permissions.can_view_annotations_all || false, - canViewOwnAnnotations: permissions.can_view_annotations_self || false + can_annotate, + can_view_annotations_all, + can_view_annotations_self }; } /** * Orient annotations to the correct scale and orientation of the annotated document. * - * @private * @param {Object} data - Scale and orientation values needed to orient annotations. * @return {void} */ - scaleAnnotations(data) { + scaleAnnotations(data: Object) { + this.unbindDOMListeners(); this.setScale(data.scale); this.render(); + this.bindDOMListeners(); } /** * Exits all annotation modes except the specified mode * - * @param {string} mode - Current annotation mode + * @param {AnnotationType} mode - Current annotation mode * @return {void} */ - toggleAnnotationMode(mode) { + toggleAnnotationMode(mode: AnnotationType) { this.hideAnnotations(); + this.unbindDOMListeners(); const currentMode = this.getCurrentAnnotationMode(); if (currentMode) { @@ -604,17 +469,18 @@ class Annotator extends EventEmitter { if (currentMode !== mode) { this.modeControllers[mode].enter(); + } else { + this.bindDOMListeners(); } } /** * Scrolls specified annotation into view * - * @private - * @param {Object} threadID - annotation threadID for thread that should scroll into view + * @param {string} threadID - annotation threadID for thread that should scroll into view * @return {void} */ - scrollToAnnotation(threadID) { + scrollToAnnotation(threadID: string) { if (!threadID) { return; } @@ -631,7 +497,6 @@ class Annotator extends EventEmitter { * Displays annotation validation error notification once on load. Does * nothing if notification was already displayed once. * - * @private * @return {void} */ handleValidationError() { @@ -647,58 +512,35 @@ class Annotator extends EventEmitter { } /** - * Handle events emitted by the annotaiton service + * Handle events emitted by the annotation service * - * @private * @param {Object} [data] - Annotation service event data * @param {string} [data.event] - Annotation service event * @param {string} [data.data] - * @return {void} */ - handleServicesErrors(data) { - let errorMessage = ''; - switch (data.reason) { - case 'read': - errorMessage = this.localized.loadError; - break; - case 'create': - errorMessage = this.localized.createError; - this.loadAnnotations(); - break; - case 'delete': - errorMessage = this.localized.deleteError; - this.loadAnnotations(); - break; - case 'authorization': - errorMessage = this.localized.authError; - break; - default: - } - + handleServicesErrors(data: Object) { if (data.error) { /* eslint-disable no-console */ console.error(ANNOTATOR_EVENT.error, data.error); /* eslint-enable no-console */ } - if (errorMessage) { - this.emit(ANNOTATOR_EVENT.error, errorMessage); - } + this.emit(ANNOTATOR_EVENT.error, this.localized.loadError); } /** * Handle events emitted by the annotation service * - * @private * @param {Object} [data] - Annotation service event data * @param {string} [data.event] - Annotation service event * @param {string} [data.data] - * @return {void} */ - handleControllerEvents(data) { + handleControllerEvents(data: Object) { switch (data.event) { - case CONTROLLER_EVENT.resetMobileDialog: - this.removeThreadFromSharedDialog(); + case CONTROLLER_EVENT.load: + this.loadAnnotations(); break; case CONTROLLER_EVENT.toggleMode: this.toggleAnnotationMode(data.mode); @@ -714,6 +556,9 @@ class Annotator extends EventEmitter { case CONTROLLER_EVENT.createThread: this.createPointThread(data.data); break; + case CONTROLLER_EVENT.error: + this.emit(ANNOTATOR_EVENT.error, data.data); + break; default: this.emit(data.event, data.data); } @@ -722,13 +567,12 @@ class Annotator extends EventEmitter { /** * Emits a generic annotator event * - * @private * @emits annotatorevent * @param {string} event - Event name * @param {Object} data - Event data * @return {void} */ - emit(event, data) { + emit(event: Event, data: ?Object) { const { annotator } = this.options; super.emit(event, data); super.emit('annotatorevent', { diff --git a/src/Annotator.scss b/src/Annotator.scss index dbb6854ec..353a76c7f 100644 --- a/src/Annotator.scss +++ b/src/Annotator.scss @@ -64,260 +64,10 @@ } } -.ba-annotation-caret { - left: 50%; - position: absolute; - - // CSS arrow for caret above container - &::after, - &::before { - border: solid transparent; - content: ' '; - height: 0; - left: 50%; - pointer-events: none; - position: absolute; - top: 0; - transform: rotate(-225deg); - width: 0; - } - - &::after { - border-color: transparent transparent $white $white; - border-width: 6px; - margin: -4px 0 0 -6px; - } - - &::before { - border-color: transparent transparent $sf-fog $sf-fog; - border-width: 6px; - margin: -5px 0 0 -6px; - } -} - -// Icon buttons -.delete-comment-btn { - svg { - fill: lighten($better-black, 10%); - } - - &:hover svg { - fill: $better-black; - } -} - -.ba-annotation-drawing-dialog, -.ba-annotation-highlight-dialog .bp-btn-plain, -.ba-annotation-highlight-dialog .bp-btn-plain:hover { - padding-left: 5px; - padding-right: 5px; - - .icon, - svg { - fill: lighten($better-black, 10%); - } - - &:hover .icon, - &:hover svg { - fill: $better-black; - } -} - -.ba-highlight-comment-btn:hover .icon { - fill: $white; -} - -.ba-add-highlight-btn:hover svg { - fill: $highlight-yellow; -} - -.ba-is-text-highlighted .ba-annotation-highlight-dialog .bp-btn-plain { - svg { - fill: $highlight-yellow; - } - - &.bp-is-active svg { - fill: $highlight-yellow-active-hover; - } - - &:hover svg { - fill: $highlight-yellow-hover; - } -} - -.bp-btn-plain.bp-btn-annotate-point.bp-is-active svg { - fill: $box-blue; -} - //------------------------------------------------------------------------------ // CSS for points and dialogs //------------------------------------------------------------------------------ -.ba-annotation-dialog, -.ba-create-annotation-dialog { - border-top: 20px solid transparent; // Transparent border for hover detection - cursor: auto; // Overrides cursor: none from annotation mode - font-family: Lato, "Helvetica Neue", Helvetica, Arial, sans-serif; - position: absolute; - text-align: left; - z-index: 130; // Annotation dialog should be above other content - - .annotation-container { - background-color: $white; - border: 1px solid $seesee; - border-radius: 4px; - overflow-x: hidden; - overflow-y: auto; - white-space: normal; - width: 282px; // Hard-coded width to solve layout issues - } - - .annotation-container section { - padding: 15px; - } - - .ba-textarea { - display: block; - font-size: 13px; - height: 34px; - line-height: 13px; - margin: 0; - max-width: 250px; - min-height: 68px; - padding: 7px; - resize: vertical; - transition: border-color linear .15s, box-shadow linear .1s; - width: 100%; - - &.ba-invalid-input { - border-color: fade-out($great-balls-of-fire, .5); - } - } - - .annotation-comment { - border-bottom: 1px solid $seesee; - margin-top: 15px; - padding-bottom: 15px; - position: relative; - - &:first-child { - margin-top: 0; - } - - &:last-child { - border-bottom: 0; - } - - .ba-annotation-comment-text { - margin-bottom: 0; - word-break: break-word; - - & p { - margin: 0; - } - } - } - - .profile-image-container { - display: inline-block; - padding-right: 5px; - vertical-align: top; - width: 37px; - - img { - border-radius: 50%; - display: block; // Remove padding from inline display - height: 32px; - width: 32px; - } - } - - .profile-container { - display: inline-block; - - .user-name { - color: $fours; - font-size: 13px; - font-weight: bold; - max-width: 175px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - - .comment-date { - color: lighten($fours, 20%); - font-size: 11px; - padding-top: 2px; - } - } - - .comment-text { - color: $fours; - font-size: 12px; - padding-top: 10px; - width: 250px; - word-wrap: break-word; - } - - .delete-confirmation { - background-color: fade-out($white, .05); - height: 100%; - left: 0; - position: absolute; - top: 0; - width: 100%; - z-index: 2; // Above the delete button - - .button-container { - margin-top: 0; - text-align: center; - } - } - - .delete-confirmation-message { - color: $fours; - font-size: 12px; - padding: 0 0 5px; - text-align: center; - } - - .button-container { - margin-top: 15px; - position: relative; - text-align: right; - width: 100%; - - .bp-btn:last-child { - margin-right: 0; - } - } - - .delete-comment-btn { - position: absolute; - right: 0; - top: 0; - - svg { - height: 18px; - width: 18px; - } - - &:focus { - box-shadow: 0 0 2px 1px fade-out($black, .8); - } - } -} - -.ba-create-annotation-dialog .ba-create-comment { - background-color: $white; - overflow-x: hidden; - overflow-y: auto; - padding: 9px; - white-space: normal; - width: 267px; // Hard-coded width to solve layout issues -} - .ba-point-annotation-marker { background-color: transparent; border-style: none; @@ -326,10 +76,6 @@ position: absolute; width: 24px; - &:hover { - z-index: 130; // Ensure activated point annotation icon is above dialog - } - svg { fill: fade-out($box-blue, .35); transition: fill .5s; @@ -340,78 +86,9 @@ } } -.ba-point-annotation-marker.ba-annotation-dialog-flipped { - path, - rect { - display: none; - } -} - -.ba-annotation-dialog-flipped { - .ba-annotation-caret { - transform: rotate(180deg); - } -} - -.ba-annotation-profile { - background-color: $tendemob-grey; - border-radius: 16px; // Circle - color: $white; - font-size: 12px; - height: 32px; - line-height: 32px; - text-align: center; - width: 32px; - - &.avatar-color-0 { - background-color: $avatar-color-1; - } - - &.avatar-color-1 { - background-color: $avatar-color-2; - } - - &.avatar-color-2 { - background-color: $avatar-color-3; - } - - &.avatar-color-3 { - background-color: $avatar-color-4; - } - - &.avatar-color-4 { - background-color: $avatar-color-5; - } - - &.avatar-color-5 { - background-color: $avatar-color-6; - } - - &.avatar-color-6 { - background-color: $avatar-color-7; - } - - &.avatar-color-7 { - background-color: $avatar-color-8; - } - - &.avatar-color-8 { - background-color: $avatar-color-9; - } -} - //------------------------------------------------------------------------------ // CSS for highlights //------------------------------------------------------------------------------ -.ba-annotation-layer-highlight, -.ba-annotation-layer-highlight-comment { - cursor: text; - left: 0; - mix-blend-mode: multiply; - position: absolute; - top: 15px; // Match 15px padding top on page -} - .ba-highlight-dialog { border-top: 20px solid transparent; // Transparent border for hover detection color: $fours; @@ -480,6 +157,15 @@ } } +.ba-annotation-layer-highlight, +.ba-annotation-layer-highlight-comment { + cursor: text; + left: 0; + mix-blend-mode: multiply; + position: absolute; + top: 15px; // Match 15px padding top on page +} + // Quad point positioning - the helper divs are positioned relative to the Rangy-created element .bp-doc .rangy-highlight { background-color: #ff0; @@ -522,12 +208,6 @@ } } -.ba-annotation-drawing-label, -.ba-annotation-highlight-label { - padding: 8px 4px; - width: 100%; -} - //------------------------------------------------------------------------------ // Draw annotation mode //------------------------------------------------------------------------------ @@ -565,6 +245,11 @@ top: 15px; // Match 15px padding top on page } +.ba-drawing-boundary { + border: 2px dashed $sevens; + position: absolute; +} + //------------------------------------------------------------------------------ // Annotation mode //------------------------------------------------------------------------------ @@ -592,5 +277,3 @@ .ba-annotation-mode .textLayer .endOfContent { pointer-events: none; } - -@import './MobileAnnotator'; diff --git a/src/BoxAnnotations.js b/src/BoxAnnotations.js index e7e341b01..a7698a3d2 100644 --- a/src/BoxAnnotations.js +++ b/src/BoxAnnotations.js @@ -1,3 +1,4 @@ +// @flow import DocAnnotator from './doc/DocAnnotator'; import ImageAnnotator from './image/ImageAnnotator'; import DrawingModeController from './controllers/DrawingModeController'; @@ -46,13 +47,22 @@ const ANNOTATOR_TYPE_CONTROLLERS = { }; class BoxAnnotations { + /** @param {Array} */ + annotators: Array; + + /** @param {Object} */ + viewerOptions: Object; + + /** @param {Object} */ + viewerConfig: Object; + /** * [constructor] * * @param {Object} viewerOptions - Viewer-specific annotator options * @return {BoxAnnotations} BoxAnnotations instance */ - constructor(viewerOptions = {}) { + constructor(viewerOptions: Object = {}) { this.annotators = ANNOTATORS; this.viewerOptions = viewerOptions; } @@ -73,7 +83,7 @@ class BoxAnnotations { * @param {Array} [disabledAnnotators] List of disabled annotators * @return {Object} Annotator for the viewer */ - getAnnotatorsForViewer(viewerName, disabledAnnotators = []) { + getAnnotatorsForViewer(viewerName: string, disabledAnnotators: Array = []) { const annotators = this.getAnnotators(); const annotatorConfig = annotators.find( (annotator) => !disabledAnnotators.includes(annotator.NAME) && annotator.VIEWER.includes(viewerName) @@ -87,11 +97,10 @@ class BoxAnnotations { * Instantiates and attaches controller instances to an annotator configuration. Does nothing if controller * has already been instantiated or the config is invalid. * - * @private * @param {Object} annotatorConfig The config where annotation type controller instances should be attached * @return {void} */ - instantiateControllers(annotatorConfig) { + instantiateControllers(annotatorConfig: Object = {}) { if (!annotatorConfig || !annotatorConfig.TYPE || annotatorConfig.CONTROLLERS) { return; } @@ -101,7 +110,9 @@ class BoxAnnotations { const annotatorTypes = this.getAnnotatorTypes(annotatorConfig); annotatorTypes.forEach((type) => { if (type in ANNOTATOR_TYPE_CONTROLLERS) { - annotatorConfig.CONTROLLERS[type] = new ANNOTATOR_TYPE_CONTROLLERS[type].CONSTRUCTOR(); + annotatorConfig.CONTROLLERS[type] = new ANNOTATOR_TYPE_CONTROLLERS[type].CONSTRUCTOR( + annotatorConfig.NAME + ); } }); /* eslint-enable no-param-reassign */ @@ -111,11 +122,10 @@ class BoxAnnotations { * Determines the supported annotation types based on the viewer configurations * or passed in options if provided, otherwise using the viewer defaults * - * @private * @param {Object} annotatorConfig The config where annotation type controller instances should be attached * @return {void} */ - getAnnotatorTypes(annotatorConfig) { + getAnnotatorTypes(annotatorConfig: Object) { if (this.viewerOptions && this.viewerOptions[annotatorConfig.NAME]) { // Sets supported annotation types based on passed in options const options = this.viewerOptions[annotatorConfig.NAME]; @@ -150,7 +160,7 @@ class BoxAnnotations { * @param {Array} [disabledAnnotators] List of disabled annotators * @return {Object|null} A copy of the annotator to use, if available */ - determineAnnotator(options, viewerConfig = {}, disabledAnnotators = []) { + determineAnnotator(options: Object, viewerConfig: Object = {}, disabledAnnotators: Array = []) { let modifiedAnnotator = null; this.viewerConfig = viewerConfig; diff --git a/src/CommentBox.js b/src/CommentBox.js deleted file mode 100644 index 8794383e7..000000000 --- a/src/CommentBox.js +++ /dev/null @@ -1,306 +0,0 @@ -import EventEmitter from 'events'; -import * as constants from './constants'; -import { hideElement, showElement, focusTextArea } from './util'; - -class CommentBox extends EventEmitter { - /** - * Text displayed in the Cancel button element. - * - * @property {string} - */ - cancelText; - - /** - * Text displayed in the Post button element. - * - * @property {string} - */ - postText; - - /** - * Placeholder text displayed in the text area element. - * - * @property {string} - */ - placeholderText; - - /** - * Reference to the comment box element. Contains buttons and text area. - * - * @property {HTMLElement} - */ - containerEl; - - /** - * Reference to the cancel button element in the comment box. - * - * @property {HTMLElement} - */ - cancelEl; - - /** - * Reference to the post button element in the comment box. - * - * @property {HTMLElement} - */ - postEl; - - /** - * Reference to the text area element in the comment box. - * - * @property {HTMLElement} - */ - textAreaEl; - - /** - * Reference to parent element that the comment box should be nested inside. - * - * @property {HTMLElement} - */ - parentEl; - - /** Whether or not we should use touch events */ - hasTouch; - - /** Whether or not user is on a mobile device */ - isMobile; - - /* Events that the comment box can emit. */ - static CommentEvents = { - cancel: 'comment_cancel', - post: 'comment_post' - }; - - /** - * Creates an element for text entry, submission and cancellation. - * - * @param {HTMLElement} parentEl - Parent element - * @param {Object} [config] - Object containing text values to be displayed to the user. - * @param {Object} config.localized - Translated strings for UI - */ - constructor(parentEl, config = {}) { - super(); - - this.parentEl = parentEl; - this.hasTouch = config.hasTouch || false; - this.isMobile = config.isMobile || false; - - this.localized = config.localized; - this.cancelText = config.localized.cancelButton; - this.postText = config.localized.postButton; - this.placeholderText = config.localized.addCommentPlaceholder; - - this.containerEl = this.createCommentBox(); - } - - /** - * Focus on the text box. - * - * @return {void} - */ - focus() { - if (this.textAreaEl) { - this.textAreaEl.focus(); - this.textAreaEl.classList.remove(constants.CLASS_INVALID_INPUT); - } - } - - /** - * Unfocus the text box. - * - * @return {void} - */ - blur() { - if (document.activeElement) { - document.activeElement.blur(); - } - } - - /** - * Clear out the text box. - * - * @return {void} - */ - clear() { - if (this.textAreaEl) { - this.textAreaEl.value = ''; - } - } - - /** - * Hide the element. - * - * @return {void} - */ - hide() { - if (this.containerEl) { - hideElement(this.containerEl); - } - } - - /** - * Show the element. - * - * @return {void} - */ - show() { - if (!this.containerEl) { - this.containerEl = this.createCommentBox(); - this.parentEl.appendChild(this.containerEl); - } - - showElement(this.containerEl); - - // Activate and move cursor in the appropriate text area if not in read-only mode - focusTextArea(this.textAreaEl); - } - - /** - * [destructor] - * - * @return {void} - */ - destroy() { - if (!this.containerEl) { - return; - } - - this.containerEl.removeEventListener('touchend', this.preventDefaultAndPropagation); - - this.containerEl.remove(); - this.parentEl = null; - this.containerEl = null; - - if (this.cancelEl) { - this.cancelEl.removeEventListener('click', this.onCancel); - this.cancelEl.removeEventListener('touchend', this.onCancel); - } - - if (this.postEl) { - this.postEl.removeEventListener('click', this.onPost); - this.postEl.removeEventListener('touchend', this.onPost); - } - - if (this.textAreaEl) { - this.textAreaEl.removeEventListener('focus', this.focus); - } - } - - //-------------------------------------------------------------------------- - // Private - //-------------------------------------------------------------------------- - - /** - * Create HTML containing the UI for the comment box. - * - * @private - * @return {HTMLElement} HTML containing UI for the comment box. - */ - createHTML() { - const containerEl = document.createElement('section'); - containerEl.classList.add(constants.CLASS_CREATE_COMMENT); - containerEl.innerHTML = ` - -
- - -
`.trim(); - - return containerEl; - } - - /** - * Stop default behaviour of an element. - * - * @param {Event} event Event created by an input event. - * @return {void} - */ - preventDefaultAndPropagation(event) { - event.preventDefault(); - event.stopPropagation(); - } - - /** - * Clear the current text in the textarea element and notify listeners. - * - * @private - * @param {Event} event Event created by input event - * @return {void} - */ - onCancel(event) { - // stops touch propogating to a click event - this.preventDefaultAndPropagation(event); - this.clear(); - this.emit(CommentBox.CommentEvents.cancel); - } - - /** - * Notify listeners of submit event and then clear textarea element. - * - * @private - * @param {Event} event Event created by input event - * @return {void} - */ - onPost(event) { - // stops touch propogating to a click event - this.preventDefaultAndPropagation(event); - - const text = this.textAreaEl.value; - if (text.trim() === '') { - this.textAreaEl.classList.add(constants.CLASS_INVALID_INPUT); - return; - } - - this.emit(CommentBox.CommentEvents.post, text); - this.clear(); - } - - /** - * Create HTML for the comment box. Assigns references to elements, attach event listeners. - * ie) Post button, cancel button - * - * @private - * @return {HTMLElement} The HTML to append to this.parentElement - */ - createCommentBox() { - const containerEl = this.createHTML(); - - // Reference HTML - this.textAreaEl = containerEl.querySelector(constants.SELECTOR_ANNOTATION_TEXTAREA); - this.cancelEl = containerEl.querySelector(constants.SELECTOR_ANNOTATION_BUTTON_CANCEL); - this.postEl = containerEl.querySelector(constants.SELECTOR_ANNOTATION_BUTTON_POST); - - // Explicit scope binding for event listeners - this.focus = this.focus.bind(this); - this.onCancel = this.onCancel.bind(this); - this.onPost = this.onPost.bind(this); - - // Add event listeners - if (this.hasTouch) { - containerEl.addEventListener('touchend', this.preventDefaultAndPropagation.bind(this)); - this.cancelEl.addEventListener('touchend', this.onCancel); - this.postEl.addEventListener('touchend', this.onPost); - } - - if (!this.isMobile) { - this.textAreaEl.addEventListener('focus', this.focus); - this.cancelEl.addEventListener('click', this.onCancel); - this.postEl.addEventListener('click', this.onPost); - } - - containerEl.addEventListener('click', this.preventDefaultAndPropagation.bind(this)); - - return containerEl; - } -} - -export default CommentBox; diff --git a/src/CreateAnnotationDialog.js b/src/CreateAnnotationDialog.js deleted file mode 100644 index dd740c898..000000000 --- a/src/CreateAnnotationDialog.js +++ /dev/null @@ -1,298 +0,0 @@ -import EventEmitter from 'events'; -import CommentBox from './CommentBox'; -import { hideElement, showElement } from './util'; -import { CLASS_MOBILE_CREATE_ANNOTATION_DIALOG, CLASS_ANNOTATION_DIALOG, CREATE_EVENT } from './constants'; - -class CreateAnnotationDialog extends EventEmitter { - /** @property {HTMLElement} - Container element for the dialog. */ - containerEl; - - /** @property {HTMLElement} - The parent container to nest the dialog element in. */ - parentEl; - - /** @property {HTMLElement} - The element containing the buttons that can creaet highlights. */ - buttonsEl; - - /** @property {CommentBox} - The comment box instance. Contains area for text input and post/cancel buttons. */ - commentBox; - - /** @property {Object} - Position, on the DOM, to align the dialog to the end of a highlight. */ - position = { - x: 0, - y: 0 - }; - - /** @property {boolean} - Whether or not we're on a mobile device. */ - isMobile; - - /** @property {boolean} - Whether or not we support touch. */ - hasTouch; - - /** @property {boolean} - Whether or not this is visible. */ - isVisible; - - /** - * A dialog used to create plain and comment highlights. - * - * [constructor] - * - * @param {HTMLElement} parentEl - Parent element - * @param {Object} [config] - For configuring the dialog. - * @param {boolean} [config.hasTouch] - True to add touch events. - * @param {boolean} [config.isMobile] - True if on a mobile device. - * @return {CreateAnnotationDialog} CreateAnnotationDialog instance - */ - constructor(parentEl, config = {}) { - super(); - - this.parentEl = parentEl; - this.isMobile = !!config.isMobile || false; - this.hasTouch = !!config.hasTouch || false; - this.localized = config.localized; - this.isVisible = false; - } - - /** - * Set the parent container to next this dialog in. - * - * @public - * @param {HTMLElement} newParentEl - The element that will contain this. - * @return {void} - */ - setParentEl(newParentEl) { - this.parentEl = newParentEl; - } - - /** - * Set the coordinates to position the dialog at, and force an update. - * - * @public - * @param {number} x - The x coordinate to position the dialog at - * @param {number} y - The y coordinate to position the dialog at - * @return {void} - */ - setPosition(x, y) { - this.position.x = x; - this.position.y = y; - this.updatePosition(); - } - - /** - * Show the dialog. Adds to the parent container if it isn't already there. - * - * @public - * @param {HTMLElement} [newParentEl] - The new parent container to nest this in. - * @return {void} - */ - show(newParentEl) { - this.isVisible = true; - if (!this.containerEl) { - this.createElement(); - } - - // Move to the correct parent element - if (newParentEl) { - this.setParentEl(newParentEl); - } - - this.setButtonVisibility(true); - - showElement(this.containerEl); - this.emit(CREATE_EVENT.init); - } - - /** - * Show the comment box in the dialog - * - * @public - * @return {void} - */ - showCommentBox() { - this.commentBox.show(); - this.commentBox.focus(); - } - - /** - * Hide the dialog, and clear out the comment box text entry. - * - * @return {void} - */ - hide() { - this.isVisible = false; - if (!this.containerEl) { - return; - } - - hideElement(this.containerEl); - - if (this.commentBox) { - this.commentBox.hide(); - this.commentBox.clear(); - } - } - - /** - * [destructor] - * - * @return {void} - */ - destroy() { - if (!this.containerEl) { - return; - } - - this.hide(); - - if (!this.isMobile) { - // Stop interacting with this element from triggering outside actions - this.containerEl.removeEventListener('click', this.stopPropagation); - this.containerEl.removeEventListener('mouseup', this.stopPropagation); - this.containerEl.removeEventListener('dblclick', this.stopPropagation); - } - - // Event listeners - if (this.hasTouch) { - this.containerEl.removeEventListener('touchend', this.stopPropagation); - } - - this.containerEl.remove(); - this.containerEl = null; - this.parentEl = null; - - if (this.commentBox) { - this.commentBox.removeListener(CommentBox.CommentEvents.post, this.onCommentPost); - this.commentBox.removeListener(CommentBox.CommentEvents.cancel, this.onCommentCancel); - this.commentBox.destroy(); - this.commentBox = null; - } - } - - //-------------------------------------------------------------------------- - // Private - //-------------------------------------------------------------------------- - - /** - * Update the position styling for the dialog so that the chevron points to - * the desired location. - * - * @return {void} - */ - updatePosition() { - if (this.isMobile) { - return; - } - - // Plus 1 pixel for caret - this.containerEl.style.left = `${this.position.x - 1 - this.containerEl.clientWidth / 2}px`; - // Plus 5 pixels for caret - this.containerEl.style.top = `${this.position.y + 5}px`; - } - - /** - * Fire an event notifying that the post button has been pressed. Clears - * out the comment box. - * - * @param {string} text - Text entered into the comment box - * @return {void} - */ - onCommentPost(text) { - this.emit(CREATE_EVENT.post, text); - if (text) { - this.commentBox.clear(); - this.commentBox.blur(); - } - } - - /** - * The cancel button has been pressed. Close the comment box, and return to - * default state. - * - * @return {void} - */ - onCommentCancel() { - this.emit(CREATE_EVENT.cancel); - this.commentBox.hide(); - this.setButtonVisibility(true); - this.updatePosition(); - } - - /** - * Hide or show the plain and comment buttons, in the dialog. - * - * @param {boolean} visible - If true, shows the plain and comment buttons - * @return {void} - */ - setButtonVisibility(visible) { - if (visible) { - showElement(this.buttonsEl); - } else { - hideElement(this.buttonsEl); - } - } - - /** - * Stop the dialog from propagating events to parent container. Pairs with - * giving focus to the text area in the comment box and clicking "Post". - * - * @param {Event} event - The DOM event coming from interacting with the element. - * @return {void} - */ - stopPropagation(event) { - event.stopPropagation(); - } - - /** - * Create the comment box element and appends it to the create dialog element - * - * @private - * @param {HTMLElement} containerEl - The parent element for the commentbox - * @return {void} - */ - setupCommentBox(containerEl) { - // Create comment boxt - const commentBox = new CommentBox(containerEl, { - hasTouch: this.hasTouch, - isMobile: this.isMobile, - localized: this.localized - }); - containerEl.appendChild(commentBox.containerEl); - - // Event listeners - commentBox.addListener(CommentBox.CommentEvents.post, this.onCommentPost.bind(this)); - commentBox.addListener(CommentBox.CommentEvents.cancel, this.onCommentCancel.bind(this)); - - // Hide comment box, by default - commentBox.hide(); - - return commentBox; - } - - /** - * Create the element containing highlight create and comment buttons, and comment box. - * - * @private - * @return {HTMLElement} The element containing Highlight creation UI - */ - createElement() { - this.containerEl = document.createElement('div'); - this.containerEl.classList.add(CLASS_MOBILE_CREATE_ANNOTATION_DIALOG); - this.containerEl.classList.add(CLASS_ANNOTATION_DIALOG); - - if (!this.isMobile) { - // Stop interacting with this element from triggering outside actions - this.containerEl.addEventListener('click', this.stopPropagation); - this.containerEl.addEventListener('mouseup', this.stopPropagation); - this.containerEl.addEventListener('dblclick', this.stopPropagation); - } - - // touch events - if (this.hasTouch) { - this.containerEl.addEventListener('touchend', this.stopPropagation); - } - - this.commentBox = this.setupCommentBox(this.containerEl); - this.containerEl.appendChild(this.commentBox.containerEl); - } -} - -export default CreateAnnotationDialog; diff --git a/src/MobileAnnotator.scss b/src/MobileAnnotator.scss deleted file mode 100644 index 455f16cd6..000000000 --- a/src/MobileAnnotator.scss +++ /dev/null @@ -1,259 +0,0 @@ -@mixin border-top-bottom { - border-color: $seesee; - border-style: solid; - border-width: 1px 0; -} - -.ba-mobile-annotation-dialog, -.ba-mobile-create-annotation-dialog { - background: white; - border-top: 0; - height: 100%; - position: absolute; - top: 0; - width: 100%; - z-index: 130; - - &.ba-animate-show-dialog { - &:not(.ba-plain-highlight) { - animation: show-dialog-small; - animation-duration: .2s; - animation-fill-mode: forwards; - - @media #{$tablet} { - animation: show-dialog-tablet; - animation-duration: .2s; - animation-fill-mode: forwards; - border-left: solid 1px $seesee; - width: 450px; - } - } - - &.ba-plain-highlight { - animation: show-highlight-dialog; - animation-duration: .2s; - animation-fill-mode: forwards; - } - } -} - -.ba-mobile-create-annotation-dialog { - bottom: 0; - height: auto; - top: auto; -} - -.ba-create-annotation-dialog.ba-mobile-annotation-dialog { - height: auto; - - .ba-annotation-highlight-dialog { - bottom: 0; - } -} - -@keyframes show-dialog-small { - 0% { - top: 100%; - } - - 100% { - top: 0%; - } -} - -@keyframes show-dialog-tablet { - 0% { - right: -50%; - } - - 100% { - right: 0%; - } -} - -@keyframes show-highlight-dialog { - 0% { - top: -48px; - } - - 100% { - top: 0; - } -} - -.ba-mobile-create-annotation-dialog, -.ba-mobile-annotation-dialog.ba-annotation-dialog { - .annotation-container { - background-color: $white; - border: 0; - border-radius: 4px; - height: 100%; - overflow-x: hidden; - overflow-y: auto; - padding: 15px; - position: absolute; - top: 48px; - width: 100%; - } - - .ba-annotation-mobile-header { - align-items: center; - background-color: $white; - display: flex; - height: 48px; - justify-content: space-between; - padding: 0; - position: absolute; - top: 0; - width: 100%; - z-index: 160; - - @include border-top-bottom; - } - - .ba-annotation-dialog-close { - background: none; - border: 0; - display: inline-block; - height: 48px; - line-height: 1; - margin-top: -1px; - padding: 3px; - vertical-align: middle; - width: 48px; - - .icon { - fill: fade-out($better-black, .25); - } - - &:hover .icon { - fill: $better-black; - } - } - - .ba-textarea { - font-size: 16px; - line-height: 16px; - min-width: 100%; - } - - .comment-text { - width: 100%; - } - - .profile-image-container { - width: 43px; - - img { - height: 40px; - width: 40px; - } - } - - .profile-container { - .user-name { - font-size: 16px; - } - - .comment-date { - font-size: 14px; - } - } - - .bp-btn { - font-size: 16; - } - - .comment-text, - .delete-confirmation-message { - font-size: 15px; - } - - .delete-comment-btn { - svg { - height: 24px; - width: 24px; - } - } - - .reply-container { - padding-bottom: 45px; - } -} - -/* Highlight dialog */ -.ba-mobile-annotation-dialog.ba-plain-highlight { - height: 47px; // includes mobile header & highlight dialog - top: auto; - - @include border-top-bottom; -} - -.ba-mobile-annotation-dialog .ba-annotation-highlight-btns, -.ba-mobile-annotation-dialog .ba-create-comment, -.ba-mobile-annotation-dialog .annotation-container section[data-section="create"], -.ba-mobile-create-annotation-dialog { - background: white; - bottom: 0; - left: 0; - padding: 15px; - position: fixed; - width: 100%; - - @include border-top-bottom; -} - -.ba-mobile-annotation-dialog .annotation-container { - @media #{$tablet} { - left: auto; - padding: 15px 0; - width: 415px; - } -} - -.ba-mobile-annotation-dialog .ba-annotation-highlight-dialog { - border: none; - color: $fours; - font-size: 16px; - line-height: 16px; - min-width: 100%; - padding: 15px; - position: absolute; - text-align: center; - z-index: 9999; - - .ba-annotation-highlight-btns { - display: flex; - justify-content: flex-start; - padding: 0; - - button { - flex-grow: 1; - padding: 15px 0; - - &:nth-child(2)::before { - border-right: 1px solid $seesee; - bottom: 17px; - content: ""; - height: 25px; - position: absolute; - right: 50%; - } - } - } - - &.cannot-annotate { - .ba-add-highlight-btn, - .ba-highlight-comment-btn { - display: none; - } - } -} - -.bp-container .ba-draw-undo-redo-container { - margin: 0; - - @media #{$tablet} { - margin: 0 auto; - } -} diff --git a/src/MomentShim.js b/src/MomentShim.js new file mode 100644 index 000000000..e9f88acc6 --- /dev/null +++ b/src/MomentShim.js @@ -0,0 +1,32 @@ +/** + * @flow + * @file Shim for moment.js + * @author Box + */ +declare var __LANGUAGE__: string; + +// This shim is here just to get pikaday working with Intl instead of moment.js +// It basically stubs out all the required methods that pikaday uses. +// May not be needed after https://github.com/dbushell/Pikaday/pull/721 +class MomentShim { + date: Date; + + constructor(date: Date | string) { + this.date = new Date(date); + } + + format() { + return this.date.toLocaleDateString(__LANGUAGE__); + } + + toDate() { + return new Date(this.date); + } + + isValid() { + return this.date.getTime() > 0; + } +} + +const momentGenerator = (date: Date | string) => new MomentShim(date); +export default momentGenerator; diff --git a/src/__tests__/AnnotationDialog-test.js b/src/__tests__/AnnotationDialog-test.js deleted file mode 100644 index 0476b4899..000000000 --- a/src/__tests__/AnnotationDialog-test.js +++ /dev/null @@ -1,1125 +0,0 @@ -/* eslint-disable no-unused-expressions */ -import Annotation from '../Annotation'; -import AnnotationDialog from '../AnnotationDialog'; -import AnnotationService from '../AnnotationService'; -import * as util from '../util'; -import * as constants from '../constants'; - -const CLASS_FLIPPED_DIALOG = 'ba-annotation-dialog-flipped'; -const SELECTOR_REPLY_TEXTAREA = '.reply-textarea'; -const SELECTOR_REPLY_CONTAINER = '.reply-container'; -const CLASS_ANIMATE_DIALOG = 'ba-animate-show-dialog'; -const SELECTOR_BUTTON_DELETE_COMMENT = '.delete-comment-btn'; -const SELECTOR_COMMENTS_CONTAINER = '.annotation-comments'; -const SELECTOR_DELETE_CONFIRMATION = '.delete-confirmation'; -const CLASS_INVALID_INPUT = 'ba-invalid-input'; - -let dialog; -const html = `
-
-
-
-
-
-
`; - -describe('Annotator', () => { - let rootElement; - let annotation; - - beforeEach(() => { - rootElement = document.createElement('div'); - rootElement.innerHTML = html; - document.body.appendChild(rootElement); - - dialog = new AnnotationDialog({ - annotatedElement: document.querySelector(constants.SELECTOR_ANNOTATED_ELEMENT), - container: document, - location: {}, - annotations: {}, - canAnnotate: true - }); - - dialog.localized = { - addCommentPlaceholder: 'add comment placeholder', - posting: 'posting' - }; - - annotation = new Annotation({ - annotationID: 1, - text: 'the preview sdk is amazing!', - user: { id: 1, name: 'user' }, - permissions: { can_delete: true } - }); - - dialog.setup(); - document.querySelector(constants.SELECTOR_ANNOTATED_ELEMENT).appendChild(dialog.element); - - dialog.emit = jest.fn(); - util.hideElement = jest.fn(); - util.showElement = jest.fn(); - dialog.isMobile = false; - }); - - afterEach(() => { - const dialogEl = document.querySelector(constants.SELECTOR_ANNOTATED_ELEMENT); - if (dialogEl && dialogEl.parentNode) { - dialogEl.parentNode.removeChild(dialogEl); - } - - dialog.element = null; - document.body.removeChild(rootElement); - dialog = null; - }); - - describe('destroy()', () => { - it('should unbind DOM listeners and cleanup its HTML', () => { - dialog.unbindDOMListeners = jest.fn(); - - dialog.destroy(); - expect(dialog.unbindDOMListeners).toBeCalled(); - expect(dialog.element).toBeNull(); - }); - }); - - describe('show()', () => { - beforeEach(() => { - dialog.position = jest.fn(); - util.focusTextArea = jest.fn(); - dialog.scrollToLastComment = jest.fn(); - dialog.showMobileDialog = jest.fn(); - dialog.canAnnotate = true; - dialog.element.classList.add(constants.CLASS_HIDDEN); - }); - - it('should show the mobile dialog if on a mobile device', () => { - dialog.isMobile = true; - dialog.show(); - expect(dialog.showMobileDialog).toBeCalled(); - expect(dialog.scrollToLastComment).toBeCalled(); - expect(dialog.emit).toBeCalledWith('annotationshow'); - }); - - it('should do nothing if the dialog is already visible ', () => { - dialog.element.classList.remove(constants.CLASS_HIDDEN); - dialog.show(); - expect(dialog.showMobileDialog).not.toBeCalled(); - expect(dialog.scrollToLastComment).not.toBeCalled(); - expect(dialog.emit).not.toBeCalledWith('annotationshow'); - }); - - it('should not reposition the dialog if the reply textarea is already active', () => { - dialog.hasAnnotations = true; - dialog.activateReply(); - - dialog.show(); - expect(dialog.scrollToLastComment).toBeCalled(); - expect(dialog.position).not.toBeCalled(); - expect(dialog.emit).not.toBeCalledWith('annotationshow'); - }); - - it('should position the dialog if not on a mobile device', () => { - dialog.hasAnnotations = true; - dialog.deactivateReply(); - const commentsTextArea = dialog.element.querySelector(constants.SELECTOR_ANNOTATION_TEXTAREA); - commentsTextArea.classList.remove(constants.CLASS_ACTIVE); - - dialog.show(); - expect(dialog.position).toBeCalled(); - expect(dialog.scrollToLastComment).toBeCalled(); - expect(dialog.emit).toBeCalledWith('annotationshow'); - }); - }); - - describe('scrollToLastComment()', () => { - beforeEach(() => { - util.focusTextArea = jest.fn(); - }); - - it('should activate the reply text area if the dialog has multiple annotations', () => { - dialog.hasAnnotations = true; - dialog.activateReply = jest.fn(); - - dialog.scrollToLastComment(); - expect(dialog.activateReply); - expect(util.focusTextArea); - }); - - it('should set the dialog scroll height to the bottom of the comments container', () => { - const annotationEl = { - scrollHeight: 500, - clientHeight: 300, - scrollTop: 0 - }; - dialog.element.querySelector = jest.fn().mockReturnValue(annotationEl); - - dialog.scrollToLastComment(); - expect(annotationEl.scrollTop).toEqual(200); - }); - - it('should set the flipped dialog scroll height to the bottom of the comments container', () => { - const annotationEl = { - scrollHeight: 500, - clientHeight: 500, - scrollTop: 0 - }; - dialog.dialogEl.classList.add('ba-annotation-dialog-flipped'); - dialog.element.querySelector = jest.fn().mockReturnValue(annotationEl); - - dialog.scrollToLastComment(); - expect(annotationEl.scrollTop).toEqual(500); - }); - }); - - describe('showMobileDialog()', () => { - beforeEach(() => { - dialog.bindDOMListeners = jest.fn(); - - dialog.container = document.createElement('div'); - dialog.container.querySelector = jest.fn().mockReturnValue(dialog.element); - - dialog.element.classList.add(constants.CLASS_MOBILE_ANNOTATION_DIALOG); - dialog.element.classList.add(constants.CLASS_HIDDEN); - - dialog.element.querySelector = jest.fn().mockReturnValue(document.createElement('div')); - }); - - it('should populate the mobile dialog if using a mobile browser', () => { - dialog.highlightDialogEl = null; - - dialog.showMobileDialog(); - expect(util.showElement).toBeCalledWith(dialog.element); - expect(dialog.bindDOMListeners).toBeCalled(); - expect(dialog.element.classList.contains(constants.CLASS_MOBILE_ANNOTATION_DIALOG)).toBeTruthy(); - expect(dialog.element.classList.contains(CLASS_ANIMATE_DIALOG)).toBeTruthy(); - }); - - it('should reset the annotation dialog to be a plain highlight if no comments are present', () => { - dialog.highlightDialogEl = {}; - - const headerEl = document.createElement('div'); - headerEl.classList.add(constants.CLASS_MOBILE_DIALOG_HEADER); - dialog.element.appendChild(headerEl); - - dialog.showMobileDialog(); - - expect(dialog.element.classList).toContain(constants.CLASS_ANNOTATION_PLAIN_HIGHLIGHT); - }); - - it('should not re-show the dialog if it is already visible', () => { - dialog.element.classList.remove(constants.CLASS_HIDDEN); - dialog.showMobileDialog(); - expect(util.showElement).not.toBeCalled(); - }); - }); - - describe('hideMobileDialog()', () => { - it('should do nothing if the dialog element does not exist', () => { - dialog.element = null; - dialog.hideMobileDialog(); - expect(util.hideElement).not.toBeCalled(); - }); - - it('should hide the mobile annotations dialog', () => { - dialog.element = document.querySelector(constants.SELECTOR_MOBILE_ANNOTATION_DIALOG); - dialog.unbindDOMListeners = jest.fn(); - dialog.hasAnnotations = true; - - dialog.hideMobileDialog(); - expect(util.hideElement).toBeCalled(); - expect(dialog.unbindDOMListeners).toBeCalled(); - }); - }); - - describe('hide()', () => { - beforeEach(() => { - dialog.isMobile = false; - dialog.element.classList.remove(constants.CLASS_HIDDEN); - dialog.unbindDOMListeners = jest.fn(); - }); - - it('should do nothing if element is already hidden', () => { - dialog.element.classList.add(constants.CLASS_HIDDEN); - dialog.hide(); - expect(util.hideElement).not.toBeCalled(); - expect(dialog.emit).not.toBeCalledWith('annotationhide'); - }); - - it('should hide dialog immediately', () => { - dialog.toggleFlippedThreadEl = jest.fn(); - dialog.hide(); - expect(util.hideElement).toBeCalledWith(dialog.element); - expect(dialog.toggleFlippedThreadEl).toBeCalled(); - expect(dialog.emit).toBeCalledWith('annotationhide'); - }); - - it('should hide the mobile dialog if using a mobile browser', () => { - dialog.isMobile = true; - dialog.hideMobileDialog = jest.fn(); - dialog.toggleFlippedThreadEl = jest.fn(); - dialog.hide(); - expect(dialog.hideMobileDialog).toBeCalled(); - expect(dialog.toggleFlippedThreadEl).toBeCalled(); - dialog.element = null; - expect(dialog.emit).toBeCalledWith('annotationhide'); - }); - }); - - describe('addAnnotation()', () => { - beforeEach(() => { - dialog.addAnnotationElement = jest.fn(); - }); - - it('should add annotation to the dialog and deactivate the reply area', () => { - dialog.addAnnotation(new Annotation({})); - expect(dialog.addAnnotationElement).toBeCalled(); - }); - - it('should hide the create section and show the show section if there are no annotations', () => { - dialog.hasAnnotations = false; - - dialog.addAnnotation(new Annotation({})); - const createSectionEl = document.querySelector(constants.SECTION_CREATE); - const showSectionEl = document.querySelector(constants.SECTION_SHOW); - expect(util.hideElement).toBeCalledWith(createSectionEl); - expect(util.showElement).toBeCalledWith(showSectionEl); - }); - }); - - describe('removeAnnotation()', () => { - it('should remove annotation element and deactivate reply', () => { - dialog.addAnnotation(annotation); - - dialog.removeAnnotation('someID'); - const annotationEl = dialog.element.querySelector('[data-annotation-id="someID"]'); - expect(annotationEl).toBeNull(); - }); - - it('should focus the reply text area', () => { - const replyTextEl = dialog.element.querySelector(SELECTOR_REPLY_TEXTAREA); - replyTextEl.focus = jest.fn(); - dialog.removeAnnotation('someID'); - expect(replyTextEl.focus).toBeCalled(); - }); - }); - - describe('element()', () => { - it('should return dialog element', () => { - expect(dialog.element).toEqual(dialog.element); - }); - }); - - describe('setup()', () => { - beforeEach(() => { - const dialogEl = document.createElement('div'); - dialog.generateDialogEl = jest.fn().mockReturnValue(dialogEl); - dialog.bindDOMListeners = jest.fn(); - dialog.addSortedAnnotations = jest.fn(); - dialog.unbindDOMListeners = jest.fn(); - dialog.isMobile = false; - }); - - it('should set up HTML element, add annotations to the dialog, and bind DOM listeners', () => { - dialog.setup([annotation], {}); - expect(dialog.element).not.toBeNull(); - expect(dialog.bindDOMListeners).toBeCalled(); - expect(dialog.threadEl).not.toBeUndefined(); - }); - - it('should not create dialog element if using a mobile browser', () => { - dialog.isMobile = true; - dialog.setup([annotation, annotation], {}); - expect(dialog.bindDOMListeners).not.toBeCalled(); - expect(dialog.addSortedAnnotations).toBeCalled(); - dialog.element = null; - }); - }); - - describe('addSortedAnnotations()', () => { - it('should add annotations to the dialog in chronological order', () => { - // Dates are provided as a string format from the API such as "2016-10-30T14:19:56", - // ensures that the method converts to a Date() format for comparison/sorting - // Hard coding dates to ensure formatting resembles API response - const threadID = AnnotationService.generateID(); - const annotation1 = new Annotation({ - annotationID: 1, - threadID, - text: 'blah', - threadNumber: '1', - user: { id: 1 }, - permissions: { can_delete: false }, - created: '2016-10-29T14:19:56' - }); - - // Ensures annotations are not provided in chronological order - const annotation3 = new Annotation({ - annotationID: 3, - threadID, - text: 'blah3', - threadNumber: '1', - user: { id: 1 }, - permissions: { can_delete: false }, - created: '2016-10-30T14:19:56' - }); - - const annotation2 = new Annotation({ - annotationID: 2, - threadID, - text: 'blah2', - threadNumber: '1', - user: { id: 1 }, - permissions: { can_delete: false }, - created: '2016-10-30T14:20:56' - }); - - // Chronologically ordered by annotationID -> [1, 3, 2] - const annotations = { - 1: annotation1, - 2: annotation2, - 3: annotation3 - }; - - dialog.addSortedAnnotations(annotations); - const annotationContainerEl = dialog.dialogEl.querySelector(SELECTOR_COMMENTS_CONTAINER); - expect(annotationContainerEl.childNodes[0].dataset.annotationId).toEqual('1'); - expect(annotationContainerEl.childNodes[1].dataset.annotationId).toEqual('3'); - expect(annotationContainerEl.childNodes[2].dataset.annotationId).toEqual('2'); - }); - }); - - describe('bindDOMListeners()', () => { - beforeEach(() => { - dialog.postReplyTextEl = dialog.element.querySelector(SELECTOR_REPLY_TEXTAREA); - dialog.annotationTextEl = dialog.element.querySelector(constants.SELECTOR_ANNOTATION_TEXTAREA); - dialog.element.addEventListener = jest.fn(); - dialog.postReplyTextEl.addEventListener = jest.fn(); - dialog.annotationTextEl.addEventListener = jest.fn(); - }); - - it('should bind ALL DOM listeners for touch enabled laptops', () => { - dialog.hasTouch = true; - - dialog.bindDOMListeners(); - expect(dialog.element.addEventListener).toBeCalledWith('keydown', expect.any(Function)); - expect(dialog.element.addEventListener).toBeCalledWith('click', expect.any(Function)); - expect(dialog.element.addEventListener).toBeCalledWith('mouseup', expect.any(Function)); - expect(dialog.element.addEventListener).toBeCalledWith('wheel', expect.any(Function)); - expect(dialog.element.addEventListener).toBeCalledWith('touchstart', dialog.clickHandler); - expect(dialog.element.addEventListener).toBeCalledWith('touchstart', dialog.stopPropagation); - expect(dialog.postReplyTextEl.addEventListener).toBeCalledWith('focus', expect.any(Function)); - expect(dialog.annotationTextEl.addEventListener).toBeCalledWith('focus', expect.any(Function)); - }); - - it('should not bind touch events if not on a touch enabled devices', () => { - dialog.bindDOMListeners(); - expect(dialog.element.addEventListener).toBeCalledWith('keydown', expect.any(Function)); - expect(dialog.element.addEventListener).toBeCalledWith('click', expect.any(Function)); - expect(dialog.element.addEventListener).toBeCalledWith('mouseup', expect.any(Function)); - expect(dialog.element.addEventListener).toBeCalledWith('wheel', expect.any(Function)); - expect(dialog.element.addEventListener).not.toBeCalledWith('touchstart', dialog.clickHandler); - expect(dialog.element.addEventListener).not.toBeCalledWith('touchstart', dialog.stopPropagation); - dialog.element = null; - }); - - it('should not bind mouseenter/leave events for mobile browsers', () => { - dialog.isMobile = true; - - dialog.bindDOMListeners(); - expect(dialog.element.addEventListener).toBeCalledWith('keydown', expect.any(Function)); - expect(dialog.element.addEventListener).toBeCalledWith('mouseup', expect.any(Function)); - expect(dialog.element.addEventListener).not.toBeCalledWith('click', expect.any(Function)); - expect(dialog.element.addEventListener).toBeCalledWith('wheel', expect.any(Function)); - dialog.element = null; - }); - }); - - describe('validateTextArea()', () => { - const textEl = document.createElement('textarea'); - - it('should do nothing if textarea is blank', () => { - textEl.classList.add(constants.CLASS_INVALID_INPUT); - dialog.validateTextArea({ target: textEl }); - expect(textEl.classList).toContain(constants.CLASS_INVALID_INPUT); - }); - - it('should remove red border around textarea', () => { - textEl.classList.add(constants.CLASS_INVALID_INPUT); - textEl.value = 'words'; - dialog.validateTextArea({ target: textEl }); - expect(textEl.classList).not.toContain(constants.CLASS_INVALID_INPUT); - }); - }); - - describe('unbindDOMListeners()', () => { - beforeEach(() => { - dialog.postReplyTextEl = dialog.element.querySelector(SELECTOR_REPLY_TEXTAREA); - dialog.annotationTextEl = dialog.element.querySelector(constants.SELECTOR_ANNOTATION_TEXTAREA); - dialog.element.removeEventListener = jest.fn(); - dialog.postReplyTextEl.removeEventListener = jest.fn(); - dialog.annotationTextEl.removeEventListener = jest.fn(); - }); - - it('should unbind ALL DOM listeners for touch enabled laptops', () => { - dialog.hasTouch = true; - - dialog.unbindDOMListeners(); - expect(dialog.element.removeEventListener).toBeCalledWith('keydown', expect.any(Function)); - expect(dialog.element.removeEventListener).toBeCalledWith('click', expect.any(Function)); - expect(dialog.element.removeEventListener).toBeCalledWith('mouseup', expect.any(Function)); - expect(dialog.element.removeEventListener).toBeCalledWith('touchstart', dialog.clickHandler); - expect(dialog.element.removeEventListener).toBeCalledWith('touchstart', dialog.stopPropagation); - expect(dialog.element.removeEventListener).toBeCalledWith('wheel', expect.any(Function)); - expect(dialog.postReplyTextEl.removeEventListener).toBeCalledWith('focus', dialog.validateTextArea); - expect(dialog.annotationTextEl.removeEventListener).toBeCalledWith('focus', dialog.validateTextArea); - }); - - it('should not bind touch events if not on a touch enabled devices', () => { - dialog.unbindDOMListeners(); - expect(dialog.element.removeEventListener).toBeCalledWith('keydown', expect.any(Function)); - expect(dialog.element.removeEventListener).toBeCalledWith('click', expect.any(Function)); - expect(dialog.element.removeEventListener).toBeCalledWith('mouseup', expect.any(Function)); - expect(dialog.element.removeEventListener).toBeCalledWith('wheel', expect.any(Function)); - expect(dialog.element.removeEventListener).not.toBeCalledWith('touchstart', dialog.clickHandler); - expect(dialog.element.removeEventListener).not.toBeCalledWith('touchstart', dialog.stopPropagation); - dialog.element = null; - }); - - it('should not bind mouseenter/leave events for mobile browsers', () => { - dialog.isMobile = true; - - dialog.unbindDOMListeners(); - expect(dialog.element.removeEventListener).toBeCalledWith('keydown', expect.any(Function)); - expect(dialog.element.removeEventListener).toBeCalledWith('mouseup', expect.any(Function)); - expect(dialog.element.removeEventListener).not.toBeCalledWith('click', expect.any(Function)); - expect(dialog.element.removeEventListener).toBeCalledWith('wheel', expect.any(Function)); - }); - }); - - describe('keydownHandler()', () => { - it('should cancel any unsaved annotations when user presses Esc on pending dialog', () => { - dialog.cancelAnnotation = jest.fn(); - dialog.hasAnnotations = false; - - dialog.keydownHandler({ - key: 'U+001B', // esc key - stopPropagation: jest.fn() - }); - expect(dialog.cancelAnnotation).toBeCalled(); - }); - - it('should hide the dialog when user presses Esc if not creating a new annotation', () => { - dialog.hide = jest.fn(); - dialog.hasAnnotations = true; - - dialog.keydownHandler({ - key: 'U+001B', // esc key - stopPropagation: jest.fn() - }); - expect(dialog.hide).toBeCalled(); - }); - - it('should scroll to the bottom area when user presses a key inside the reply area', () => { - dialog.scrollToLastComment = jest.fn(); - - dialog.keydownHandler({ - key: ' ', // space - target: dialog.element.querySelector(SELECTOR_REPLY_TEXTAREA), - stopPropagation: jest.fn() - }); - expect(dialog.scrollToLastComment).toBeCalled(); - }); - }); - - describe('stopPropagation()', () => { - it('should stop propagation on the event', () => { - const event = { - stopPropagation: jest.fn() - }; - - dialog.stopPropagation(event); - expect(event.stopPropagation).toBeCalled(); - }); - }); - - describe('enable()', () => { - it('should enable all buttons in specified annotation element', () => { - dialog.element = document.createElement('div'); - - const annotationEl = document.createElement('div'); - annotationEl.setAttribute('data-annotation-id', '123'); - dialog.element.appendChild(annotationEl); - - // Add buttons - const btn = document.createElement('button'); - btn.classList.add(constants.CLASS_DISABLED); - annotationEl.querySelectorAll = jest.fn().mockReturnValue([btn, btn]); - - const wrongEl = document.createElement('div'); - wrongEl.setAttribute('data-annotation-id', 'invalid'); - wrongEl.querySelectorAll = jest.fn(); - dialog.element.appendChild(wrongEl); - - dialog.enable('123'); - expect(annotationEl.querySelectorAll).toBeCalled(); - expect(btn.classList).not.toContain(constants.CLASS_DISABLED); - expect(wrongEl.querySelectorAll).not.toBeCalled(); - }); - }); - - describe('disable()', () => { - it('should disable all buttons in specified annotation element', () => { - dialog.element = document.createElement('div'); - - const annotationEl = document.createElement('div'); - annotationEl.setAttribute('data-annotation-id', '123'); - dialog.element.appendChild(annotationEl); - - // Add buttons - const btn = document.createElement('button'); - annotationEl.querySelectorAll = jest.fn().mockReturnValue([btn, btn]); - - const wrongEl = document.createElement('div'); - wrongEl.setAttribute('data-annotation-id', 'invalid'); - wrongEl.querySelectorAll = jest.fn(); - dialog.element.appendChild(wrongEl); - - dialog.disable('123'); - expect(annotationEl.querySelectorAll).toBeCalled(); - expect(btn.classList).toContain(constants.CLASS_DISABLED); - expect(wrongEl.querySelectorAll).not.toBeCalled(); - }); - }); - - describe('clickHandler()', () => { - let event; - - beforeEach(() => { - event = { - stopPropagation: jest.fn(), - preventDefault: jest.fn(), - target: document.createElement('div') - }; - - dialog.postAnnotation = jest.fn(); - dialog.cancelAnnotation = jest.fn(); - dialog.deactivateReply = jest.fn(); - dialog.activateReply = jest.fn(); - util.findClosestDataType = jest.fn(); - dialog.showDeleteConfirmation = jest.fn(); - dialog.hideDeleteConfirmation = jest.fn(); - dialog.deleteAnnotation = jest.fn(); - dialog.postReply = jest.fn(); - dialog.hideMobileDialog = jest.fn(); - - dialog.isMobile = false; - dialog.element.classList.remove(constants.CLASS_HIDDEN); - }); - - it('should only stop propagation on a desktop device', () => { - dialog.clickHandler(event); - expect(event.stopPropagation).toBeCalled(); - expect(event.preventDefault).not.toBeCalled(); - }); - - it('should only stop propagation on a mobile device', () => { - dialog.isMobile = true; - dialog.clickHandler(event); - expect(event.stopPropagation).toBeCalled(); - expect(event.preventDefault).not.toBeCalled(); - }); - - it('should only prevent default on button clicks for mobile devices', () => { - event.target = document.createElement('button'); - dialog.isMobile = true; - dialog.clickHandler(event); - expect(event.stopPropagation).toBeCalled(); - expect(event.preventDefault).toBeCalled(); - }); - - it('should post annotation when post annotation button is clicked', () => { - util.findClosestDataType = jest.fn().mockReturnValue(constants.DATA_TYPE_POST); - - dialog.clickHandler(event); - expect(dialog.postAnnotation).toBeCalled(); - }); - - it('should cancel annotation when cancel annotation button is clicked', () => { - util.findClosestDataType = jest.fn().mockReturnValue(constants.DATA_TYPE_CANCEL); - dialog.clickHandler(event); - expect(dialog.cancelAnnotation).toBeCalled(); - }); - - it('should cancel annotation when mobile dialog close button is clicked', () => { - util.findClosestDataType = jest.fn().mockReturnValue(constants.DATA_TYPE_MOBILE_CLOSE); - dialog.clickHandler(event); - expect(dialog.cancelAnnotation).toBeCalled(); - }); - - it('should activate reply area when textarea is clicked', () => { - util.findClosestDataType = jest.fn().mockReturnValue(constants.DATA_TYPE_REPLY_TEXTAREA); - - dialog.clickHandler(event); - expect(dialog.activateReply).toBeCalled(); - }); - - it('should deactivate reply area when cancel reply button is clicked', () => { - util.findClosestDataType = jest.fn().mockReturnValue(constants.DATA_TYPE_CANCEL_REPLY); - - dialog.clickHandler(event); - expect(dialog.deactivateReply).toBeCalledWith(true); - }); - - it('should post reply when post reply button is clicked', () => { - util.findClosestDataType = jest.fn().mockReturnValue(constants.DATA_TYPE_POST_REPLY); - - dialog.clickHandler(event); - expect(dialog.postReply).toBeCalled(); - }); - - it('should show delete confirmation when delete button is clicked', () => { - util.findClosestDataType = jest - .fn() - .mockReturnValueOnce(constants.DATA_TYPE_DELETE) - .mockReturnValue('someID'); - - dialog.clickHandler(event); - expect(dialog.showDeleteConfirmation).toBeCalledWith('someID'); - }); - - it('should cancel deletion when cancel delete button is clicked', () => { - util.findClosestDataType = jest - .fn() - .mockReturnValueOnce(constants.DATA_TYPE_CANCEL_DELETE) - .mockReturnValue('someID'); - - dialog.clickHandler(event); - expect(dialog.hideDeleteConfirmation).toBeCalledWith('someID'); - }); - - it('should confirm deletion when confirm delete button is clicked', () => { - util.findClosestDataType = jest - .fn() - .mockReturnValueOnce(constants.DATA_TYPE_CONFIRM_DELETE) - .mockReturnValue('someID'); - - dialog.clickHandler(event); - expect(dialog.deleteAnnotation).toBeCalledWith('someID'); - }); - - it('should do nothing if dataType does not match any button in the annotation dialog', () => { - util.findClosestDataType = jest.fn().mockReturnValue(null); - - dialog.clickHandler(event); - expect(dialog.postAnnotation).not.toBeCalled(); - expect(dialog.postReply).not.toBeCalled(); - expect(dialog.cancelAnnotation).not.toBeCalled(); - expect(dialog.deactivateReply).not.toBeCalled(); - expect(dialog.activateReply).not.toBeCalled(); - expect(dialog.postReply).not.toBeCalled(); - expect(dialog.showDeleteConfirmation).not.toBeCalled(); - expect(dialog.hideDeleteConfirmation).not.toBeCalled(); - expect(dialog.deleteAnnotation).not.toBeCalled(); - }); - }); - - describe('addAnnotationElement()', () => { - it('should add an annotation comment if text is present', () => { - dialog.addAnnotationElement( - new Annotation({ - annotationID: 1, - text: 'the preview sdk is awesome!', - user: {}, - permissions: {} - }) - ); - const annotationComment = document.querySelector(constants.SELECTOR_ANNOTATION_COMMENT_TEXT); - expect(annotationComment.textContent).toContain('the preview sdk is awesome!'); - }); - - it('should display the posting message if the user id is 0', () => { - dialog.addAnnotationElement( - new Annotation({ - annotationID: 1, - text: 'the preview sdk is awesome!', - user: { id: 0 }, - permissions: {} - }) - ); - const username = document.querySelector(constants.SELECTOR_USER_NAME); - expect(username.textContent).toContain(dialog.localized.posting); - }); - - it('should display user name if the user id is not 0', () => { - dialog.addAnnotationElement( - new Annotation({ - annotationID: 1, - text: 'the preview sdk is awesome!', - user: { id: 1, name: 'user' }, - permissions: {} - }) - ); - const username = document.querySelector(constants.SELECTOR_USER_NAME); - expect(username.textContent).toContain('user'); - }); - - it('should not the delete icon if the user does not have delete permissions', () => { - dialog.addAnnotationElement( - new Annotation({ - annotationID: 1, - text: 'the preview sdk is amazing!', - user: { id: 1, name: 'user' }, - permissions: { can_delete: false } - }) - ); - const deleteButton = document.querySelector(SELECTOR_BUTTON_DELETE_COMMENT); - expect(deleteButton).toBeNull(); - }); - - it('should not add the delete icon if the delete permission is not specified', () => { - dialog.addAnnotationElement( - new Annotation({ - annotationID: 1, - text: 'the preview sdk is amazing!', - user: { id: 1, name: 'user' }, - permissions: {} - }) - ); - const deleteButton = document.querySelector(SELECTOR_BUTTON_DELETE_COMMENT); - expect(deleteButton).toBeNull(); - }); - - it('should make delete icon visible if the user has delete permission', () => { - dialog.addAnnotationElement( - new Annotation({ - annotationID: 1, - text: 'the preview sdk is amazing!', - user: { id: 1, name: 'user' }, - permissions: { can_delete: true } - }) - ); - const deleteButton = document.querySelector(SELECTOR_BUTTON_DELETE_COMMENT); - expect(deleteButton.classList).not.toContain(constants.CLASS_HIDDEN); - }); - - it('should hide the delete confirmation UI by default', () => { - dialog.addAnnotationElement( - new Annotation({ - annotationID: 1, - text: 'the preview sdk is amazing!', - user: { id: 1, name: 'user' }, - permissions: { can_delete: true } - }) - ); - const deleteConfirmation = document.querySelector(SELECTOR_DELETE_CONFIRMATION); - expect(deleteConfirmation.classList).toContain(constants.CLASS_HIDDEN); - }); - - it('should add a
for each newline', () => { - const withBreaks = ` - - - yay, three breaks!`; - - dialog.addAnnotationElement( - new Annotation({ - annotationID: 1, - text: withBreaks, - user: { id: 1, name: 'user' }, - permissions: { can_delete: true } - }) - ); - const breaks = document.querySelectorAll(`${constants.SELECTOR_ANNOTATION_COMMENT_TEXT} br`); - expect(breaks.length === 3).toBeTruthy(); - }); - - it('should respect symbols added to the text', () => { - const text = 'I can add symbols &&&'; - dialog.addAnnotationElement( - new Annotation({ - annotationID: 1, - text, - user: {}, - permissions: {} - }) - ); - const annotationComment = document.querySelector(constants.SELECTOR_ANNOTATION_COMMENT_TEXT); - expect(annotationComment.textContent).toEqual(text); - expect(annotationComment.textContent).toContain('&&&'); - }); - }); - - describe('postAnnotation()', () => { - it('should not post an annotation to the dialog if it has no text', () => { - const annotationTextEl = dialog.element.querySelector(constants.SELECTOR_ANNOTATION_TEXTAREA); - dialog.postAnnotation(); - expect(dialog.emit).not.toBeCalled(); - expect(annotationTextEl.classList).toContain(CLASS_INVALID_INPUT); - }); - - it('should post an annotation to the dialog if it has text', () => { - document.querySelector('textarea').innerHTML += 'the preview SDK is great!'; - - dialog.postAnnotation(); - expect(dialog.emit).toBeCalledWith('annotationcreate', { text: 'the preview SDK is great!' }); - }); - - it('should clear the annotation text element after posting', () => { - const annotationTextEl = document.querySelector('textarea'); - annotationTextEl.innerHTML += 'the preview SDK is great!'; - - dialog.postAnnotation(); - expect(annotationTextEl.value).toEqual(''); - }); - }); - - describe('cancelAnnotation()', () => { - it('should emit the annotationcancel message', () => { - dialog.cancelAnnotation(); - expect(dialog.emit).toBeCalledWith('annotationcancel'); - }); - }); - - describe('activateReply()', () => { - it('should do nothing if the dialogEl does not exist', () => { - dialog.dialogEl = null; - dialog.activateReply(); - expect(util.showElement).not.toBeCalled(); - }); - - it('should do nothing if reply textarea is already active', () => { - const replyTextEl = dialog.element.querySelector(SELECTOR_REPLY_TEXTAREA); - replyTextEl.classList.add(constants.CLASS_ACTIVE); - dialog.activateReply(); - expect(util.showElement).not.toBeCalled(); - }); - - it('should do nothing if reply text area does not exist', () => { - const replyTextEl = dialog.element.querySelector(SELECTOR_REPLY_TEXTAREA); - replyTextEl.parentNode.removeChild(replyTextEl); - dialog.activateReply(); - expect(util.showElement).not.toBeCalled(); - }); - - it('should show the correct UI when the reply textarea is activated', () => { - document.querySelector('textarea').textContent = 'the preview SDK is great!'; - dialog.addAnnotationElement(annotation); - const replyTextEl = document.querySelector(SELECTOR_REPLY_TEXTAREA); - replyTextEl.classList.remove(constants.CLASS_ACTIVE); - - dialog.activateReply(); - expect(replyTextEl.classList).toContain(constants.CLASS_ACTIVE); - }); - }); - - describe('deactivateReply()', () => { - it('should do nothing if element does not exist', () => { - dialog.dialogEl = null; - util.resetTextarea = jest.fn(); - - dialog.deactivateReply(); - expect(util.resetTextarea).not.toBeCalled(); - }); - - it('should do nothing if reply text area does not exist', () => { - const replyTextEl = dialog.element.querySelector(SELECTOR_REPLY_CONTAINER); - replyTextEl.parentNode.removeChild(replyTextEl); - dialog.deactivateReply(); - expect(util.showElement).not.toBeCalled(); - }); - - it('should show the correct UI when the reply textarea is deactivated', () => { - dialog.addAnnotationElement(annotation); - const replyTextEl = document.querySelector(SELECTOR_REPLY_TEXTAREA); - const buttonContainer = replyTextEl.parentNode.querySelector(constants.SELECTOR_BUTTON_CONTAINER); - - dialog.deactivateReply(); - expect(replyTextEl.classList).not.toContain(constants.CLASS_ACTIVE); - expect(buttonContainer.classList).toContain(constants.CLASS_HIDDEN); - }); - }); - - describe('postReply()', () => { - it('should not post reply to the dialog if it has no text', () => { - dialog.addAnnotationElement(annotation); - dialog.activateReply(); - const replyTextEl = dialog.element.querySelector(SELECTOR_REPLY_TEXTAREA); - - dialog.postReply(); - expect(dialog.emit).not.toBeCalled(); - expect(replyTextEl.classList).toContain(CLASS_INVALID_INPUT); - }); - - it('should post a reply to the dialog if it has text', () => { - dialog.addAnnotationElement(annotation); - const replyTextEl = document.querySelector(SELECTOR_REPLY_TEXTAREA); - dialog.activateReply(); - replyTextEl.innerHTML += 'the preview SDK is great!'; - - dialog.postReply(); - expect(dialog.emit).toBeCalledWith('annotationcreate', { text: 'the preview SDK is great!' }); - }); - - it('should clear the reply text element after posting', () => { - dialog.addAnnotationElement(annotation); - const replyTextEl = document.querySelector(SELECTOR_REPLY_TEXTAREA); - dialog.activateReply(); - replyTextEl.innerHTML += 'the preview SDK is great!'; - replyTextEl.focus = jest.fn(); - - dialog.postReply(); - expect(replyTextEl.value).toEqual(''); - expect(replyTextEl.focus).toBeCalled(); - }); - }); - - describe('showDeleteConfirmation()', () => { - it('should show the correct UI when a user clicks on delete', () => { - dialog.addAnnotationElement(annotation); - dialog.showDeleteConfirmation(1); - expect(util.showElement).toBeCalled(); - }); - }); - - describe('hideDeleteConfirmation()', () => { - it('should show the correct UI when a user clicks cancel in the delete confirmation', () => { - dialog.addAnnotationElement( - new Annotation({ - annotationID: 1, - text: 'the preview sdk is amazing!', - user: { id: 1, name: 'user' }, - permissions: { can_delete: true } - }) - ); - dialog.showDeleteConfirmation(1); - - dialog.hideDeleteConfirmation(1); - expect(util.hideElement).toBeCalled(); - }); - }); - - describe('deleteAnnotation()', () => { - it('should emit the annotationdelete message', () => { - dialog.addAnnotationElement( - new Annotation({ - annotationID: 1, - text: 'the preview sdk is amazing!', - user: { id: 1, name: 'user' }, - permissions: { can_delete: true } - }) - ); - - dialog.deleteAnnotation(1); - expect(dialog.emit).toBeCalledWith('annotationdelete', { annotationID: 1 }); - }); - }); - - describe('generateDialogEl', () => { - it('should generate a blank annotations dialog element', () => { - const dialogEl = dialog.generateDialogEl(0); - const createSectionEl = dialogEl.querySelector(constants.SECTION_CREATE); - const showSectionEl = dialogEl.querySelector(constants.SECTION_SHOW); - expect(createSectionEl.classList).not.toContain(constants.CLASS_HIDDEN); - expect(showSectionEl.classList).toContain(constants.CLASS_HIDDEN); - }); - - it('should generate an annotations dialog element with annotations', () => { - const dialogEl = dialog.generateDialogEl(1); - const createSectionEl = dialogEl.querySelector(constants.SECTION_CREATE); - const showSectionEl = dialogEl.querySelector(constants.SECTION_SHOW); - expect(createSectionEl.classList).toContain(constants.CLASS_HIDDEN); - expect(showSectionEl.classList).not.toContain(constants.CLASS_HIDDEN); - }); - - it('should not add the create section nor the reply container in read-only mode', () => { - dialog.canAnnotate = false; - const dialogEl = dialog.generateDialogEl(1); - - const createSectionEl = dialogEl.querySelector(constants.SECTION_CREATE); - const replyContainerEl = dialogEl.querySelector(SELECTOR_REPLY_CONTAINER); - const showSectionEl = dialogEl.querySelector(constants.SECTION_SHOW); - expect(createSectionEl).toBeNull(); - expect(replyContainerEl).toBeNull(); - expect(showSectionEl.classList).not.toContain(constants.CLASS_HIDDEN); - }); - }); - - describe('flipDialog()', () => { - const containerHeight = 5; - - beforeEach(() => { - dialog.element = document.createElement('div'); - dialog.element.querySelector = jest.fn().mockReturnValue(document.createElement('div')); - dialog.fitDialogHeightInPage = jest.fn(); - dialog.toggleFlippedThreadEl = jest.fn(); - }); - - afterEach(() => { - dialog.element = null; - }); - - it('should keep the dialog below the annotation icon if the annotation is in the top half of the viewport', () => { - const { top, bottom } = dialog.flipDialog(2, containerHeight); - expect(dialog.element.classList).not.toContain(CLASS_FLIPPED_DIALOG); - expect(top).not.toEqual(''); - expect(bottom).toEqual(''); - expect(dialog.fitDialogHeightInPage).toBeCalled(); - expect(dialog.toggleFlippedThreadEl).toBeCalled(); - }); - - it('should flip the dialog above the annotation icon if the annotation is in the lower half of the viewport', () => { - const { top, bottom } = dialog.flipDialog(4, containerHeight); - expect(dialog.element.classList).toContain(CLASS_FLIPPED_DIALOG); - expect(top).toEqual(''); - expect(bottom).not.toEqual(''); - }); - }); - - describe('toggleFlippedThreadEl()', () => { - beforeEach(() => { - dialog.element.classList.remove(constants.CLASS_HIDDEN); - dialog.threadEl = document.createElement('div'); - }); - - it('should do nothing if the dialog is not flipped', () => { - dialog.toggleFlippedThreadEl(); - expect(dialog.threadEl.classList).not.toContain(CLASS_FLIPPED_DIALOG); - }); - - it('should reset thread icon if dialog is flipped and hidden', () => { - dialog.element.classList.add(CLASS_FLIPPED_DIALOG); - dialog.toggleFlippedThreadEl(); - expect(dialog.threadEl.classList).toContain(CLASS_FLIPPED_DIALOG); - }); - - it('should flip thread icon if dialog is flipped and not hidden', () => { - dialog.element.classList.add(CLASS_FLIPPED_DIALOG); - dialog.element.classList.add(constants.CLASS_HIDDEN); - dialog.toggleFlippedThreadEl(); - expect(dialog.threadEl.classList).not.toContain(CLASS_FLIPPED_DIALOG); - }); - }); - - describe('fitDialogHeightInPage()', () => { - it('should allow scrolling on annotations dialog if file is a powerpoint', () => { - dialog.dialogEl = { - style: {}, - querySelector: jest.fn().mockReturnValue(null) - }; - dialog.container = { clientHeight: 100 }; - dialog.fitDialogHeightInPage(); - expect(dialog.dialogEl.style.maxHeight).toEqual('20px'); - }); - - it('should allow scrolling on annotations dialog if file is a powerpoint', () => { - const commentsEl = document.createElement('div'); - dialog.dialogEl = { - style: {}, - querySelector: jest.fn().mockReturnValue(commentsEl) - }; - dialog.container = { clientHeight: 100 }; - dialog.fitDialogHeightInPage(); - expect(dialog.dialogEl.style.maxHeight).toEqual('20px'); - expect(commentsEl.style.maxHeight).toEqual('20px'); - }); - }); -}); diff --git a/src/__tests__/AnnotationService-test.js b/src/__tests__/AnnotationService-test.js deleted file mode 100644 index 16cfb912c..000000000 --- a/src/__tests__/AnnotationService-test.js +++ /dev/null @@ -1,476 +0,0 @@ -/* eslint-disable no-unused-expressions */ -import fetchMock from 'fetch-mock'; -import Annotation from '../Annotation'; -import AnnotationService from '../AnnotationService'; -import * as util from '../util'; - -const API_HOST = 'https://app.box.com/api'; - -let annotationService; - -describe('AnnotationService', () => { - beforeEach(() => { - annotationService = new AnnotationService({ - apiHost: API_HOST, - fileId: 1, - token: 'someToken', - canAnnotate: true - }); - annotationService.emit = jest.fn(); - }); - - afterEach(() => { - fetchMock.restore(); - }); - - describe('generateID()', () => { - it('should return a rfc4122v4-compliant GUID', () => { - const GUID = AnnotationService.generateID(); - const regex = /^[a-z0-9]{8}-[a-z0-9]{4}-4[a-z0-9]{3}-[a-z0-9]{4}-[a-z0-9]{12}$/i; - expect(GUID.match(regex).length).toBeGreaterThan(0); - }); - - it('should (almost always) return unique GUIDs', () => { - // eslint-disable-next-line no-self-compare - expect(AnnotationService.generateID() === AnnotationService.generateID()).toBeFalsy(); - }); - }); - - describe('create()', () => { - const annotationToSave = new Annotation({ - fileVersionId: 2, - threadID: AnnotationService.generateID(), - type: 'point', - threadNumber: '1', - text: 'blah', - location: { x: 0, y: 0 } - }); - const url = `${API_HOST}/2.0/annotations`; - - it('should create annotation and return created object', () => { - fetchMock.mock(url, { - body: { - id: AnnotationService.generateID(), - item: { - id: annotationToSave.fileVersionId - }, - details: { - type: annotationToSave.type, - threadID: annotationToSave.threadID, - location: annotationToSave.location - }, - thread: annotationToSave.threadNumber, - message: annotationToSave.text, - created_by: {} - } - }); - - return annotationService.create(annotationToSave).then((createdAnnotation) => { - expect(createdAnnotation.fileVersionId).toEqual(annotationToSave.fileVersionId); - expect(createdAnnotation.threadID).toEqual(annotationToSave.threadID); - expect(createdAnnotation.threadNumber).toEqual(annotationToSave.threadNumber); - expect(createdAnnotation.type).toEqual(annotationToSave.type); - expect(createdAnnotation.text).toEqual(annotationToSave.text); - expect(createdAnnotation.location.x).toEqual(annotationToSave.location.x); - expect(createdAnnotation.location.y).toEqual(annotationToSave.location.y); - expect(annotationService.emit).not.toBeCalled(); - }); - }); - - it('should reject with an error if there was a problem creating', () => { - fetchMock.mock(url, { - body: { - type: 'error' - } - }); - - return annotationService.create(annotationToSave).then( - () => { - throw new Error('Annotation should not be returned'); - }, - (error) => { - expect(error.message).toEqual('Could not create annotation'); - expect(annotationService.emit).toBeCalledWith('annotationerror', { - reason: 'create', - error: expect.any(String) - }); - } - ); - }); - }); - - describe('read()', () => { - const url = `${API_HOST}/2.0/files/1/annotations?version=2&fields=item,thread,details,message,created_by,created_at,modified_at,permissions`; - - it('should return array of annotations for the specified file and file version', () => { - const annotation1 = new Annotation({ - fileVersionId: 2, - threadID: AnnotationService.generateID(), - type: 'point', - text: 'blah', - threadNumber: '1', - location: { x: 0, y: 0 } - }); - - const annotation2 = new Annotation({ - fileVersionId: 2, - threadID: AnnotationService.generateID(), - type: 'highlight', - text: 'blah2', - threadNumber: '2', - location: { x: 0, y: 0 } - }); - - fetchMock.mock(url, { - body: { - entries: [ - { - id: AnnotationService.generateID(), - item: { - id: annotation1.fileVersionId - }, - details: { - type: annotation1.type, - threadID: annotation1.threadID, - location: annotation1.location - }, - message: annotation1.text, - thread: annotation1.threadNumber, - created_by: {} - }, - { - id: AnnotationService.generateID(), - item: { - id: annotation2.fileVersionId - }, - details: { - type: annotation2.type, - threadID: annotation2.threadID, - location: annotation2.location - }, - message: annotation2.text, - threadNumber: annotation2.threadNumber, - created_by: {} - } - ] - } - }); - - return annotationService.read(2).then((annotations) => { - expect(Object.keys(annotations).length).toEqual(2); - - const firstAnnotationId = Object.keys(annotations)[0]; - const createdAnnotation1 = annotations[firstAnnotationId]; - expect(createdAnnotation1.text).toEqual(annotation1.text); - - const secondAnnotationId = Object.keys(annotations)[1]; - const createdAnnotation2 = annotations[secondAnnotationId]; - expect(createdAnnotation2.text).toEqual(annotation2.text); - }); - }); - - it('should reject with an error if there was a problem reading', () => { - fetchMock.mock(url, { - body: { - type: 'error' - } - }); - - return annotationService.read(2).then( - () => { - throw new Error('Annotations should not be returned'); - }, - (error) => { - expect(error.message).toEqual('Could not read annotations from file version with ID 2'); - } - ); - }); - }); - - describe('delete()', () => { - const url = `${API_HOST}/2.0/annotations/3`; - - it('should successfully delete the annotation', () => { - fetchMock.mock(url, 204); - return annotationService.delete(3).then(() => { - expect(fetchMock.called(url)).toBeTruthy(); - expect(annotationService.emit).not.toBeCalled(); - }); - }); - - it('should reject with an error if there was a problem deleting', () => { - fetchMock.mock(url, { - body: { - type: 'error' - } - }); - - return annotationService.delete(3).then( - () => { - throw new Error('Annotation should not have been deleted'); - }, - (error) => { - expect(error.message).toEqual('Could not delete annotation with ID 3'); - expect(annotationService.emit).toBeCalledWith('annotationerror', { - reason: 'delete', - error: expect.any(String) - }); - } - ); - }); - }); - - describe('getThreadMap()', () => { - it('should call read and then generate a map of thread ID to annotations in those threads', () => { - const annotation1 = new Annotation({ - fileVersionId: 2, - annotationID: 1, - type: 'point', - text: 'blah', - threadNumber: '1', - threadID: '123abc', - location: { x: 0, y: 0 } - }); - - const annotation2 = new Annotation({ - fileVersionId: 2, - annotationID: 2, - type: 'point', - text: 'blah2', - threadNumber: '2', - threadID: '456def', - location: { x: 0, y: 0 } - }); - - const annotation3 = new Annotation({ - fileVersionId: 2, - annotationID: 3, - type: 'point', - text: 'blah3', - threadNumber: '1', - threadID: '123abc', - location: { x: 0, y: 0 } - }); - - const threads = { - 1: annotation1, - 2: annotation2, - 3: annotation3 - }; - annotationService.read = jest.fn().mockResolvedValue(threads); - annotationService.createThreadMap = jest.fn().mockReturnValue(threads); - - return annotationService.getThreadMap(2).then(() => { - expect(annotationService.createThreadMap).toBeCalled(); - }); - }); - }); - - describe('createThreadMap()', () => { - it('should create a thread map with the correct annotations', () => { - const annotation1 = new Annotation({ - fileVersionId: 2, - annotationID: 1, - type: 'point', - text: 'blah', - threadNumber: '1', - threadID: '123abc', - location: { x: 0, y: 0 } - }); - - const annotation2 = new Annotation({ - fileVersionId: 2, - annotationID: 2, - type: 'point', - text: 'blah2', - threadNumber: '2', - threadID: '456def', - location: { x: 0, y: 0 } - }); - - const annotation3 = new Annotation({ - fileVersionId: 2, - annotationID: 3, - type: 'point', - text: 'blah3', - threadNumber: '1', - threadID: '123abc', - location: { x: 0, y: 0 } - }); - - const annotation4 = new Annotation({ - fileVersionId: 2, - annotationID: 4, - type: 'point', - text: 'blah4', - threadNumber: '1', - threadID: '123abc', - location: { x: 0, y: 0 } - }); - - const threadMap = annotationService.createThreadMap([annotation1, annotation2, annotation3, annotation4]); - - expect(Object.keys(threadMap[annotation1.threadID]).length).toEqual(3); - - const thread = threadMap[annotation1.threadID]; - expect(thread[1]).toStrictEqual(annotation1); - expect(thread[1].threadNumber).toEqual(annotation1.threadNumber); - expect(thread).not.toContain(annotation2); - }); - }); - - describe('createAnnotation()', () => { - it('should call the Annotation constructor', () => { - const data = { - fileVersionId: 2, - threadID: 1, - type: 'point', - text: 'blah3', - threadNumber: '1', - location: { x: 0, y: 0 }, - created: Date.now(), - item: { id: 1 }, - details: { threadID: 1 }, - created_by: { id: 1 } - }; - const annotation1 = annotationService.createAnnotation(data); - - expect(annotation1 instanceof Annotation).toBeTruthy(); - }); - }); - - describe('readFromMarker()', () => { - it('should get subsequent annotations if a marker is present', () => { - const markerUrl = annotationService.getReadUrl(2, 'a', 1); - - const annotation2 = new Annotation({ - fileVersionId: 2, - threadID: AnnotationService.generateID(), - type: 'highlight', - text: 'blah2', - threadNumber: '1', - location: { x: 0, y: 0 } - }); - - fetchMock.mock(markerUrl, { - body: { - entries: [ - { - id: AnnotationService.generateID(), - item: { - id: annotation2.fileVersionId - }, - details: { - type: annotation2.type, - threadID: annotation2.threadID, - location: annotation2.location - }, - thread: annotation2.threadNumber, - message: annotation2.text, - created_by: {} - } - ] - } - }); - - let resolve; - let reject; - const promise = new Promise((success, failure) => { - resolve = success; - reject = failure; - }); - - annotationService.annotations = []; - annotationService.readFromMarker(resolve, reject, 2, 'a', 1); - promise.then((result) => { - expect(Object.keys(result).length).toEqual(1); - const firstAnnotation = util.getFirstAnnotation(result); - expect(firstAnnotation.text).toEqual(annotation2.text); - expect(firstAnnotation.threadNumber).toEqual(annotation2.threadNumber); - }); - }); - - it('should reject with an error and show a notification if there was a problem reading', () => { - const markerUrl = annotationService.getReadUrl(2, 'a', 1); - - fetchMock.mock(markerUrl, { - body: { - type: 'error' - } - }); - - let resolve; - let reject; - const promise = new Promise((success, failure) => { - resolve = success; - reject = failure; - }); - - annotationService.annotations = []; - annotationService.readFromMarker(resolve, reject, 2, 'a', 1); - return promise.then( - () => { - throw new Error('Annotation should not have been deleted'); - }, - (error) => { - expect(error.message).toEqual('Could not read annotations from file version with ID 2'); - expect(annotationService.emit).toBeCalledWith('annotationerror', { - reason: 'read', - error: expect.any(String) - }); - } - ); - }); - - it('should reject with an error and show a notification if the token is invalid', () => { - const markerUrl = annotationService.getReadUrl(2, 'a', 1); - - fetchMock.mock(markerUrl, 401); - - let resolve; - let reject; - const promise = new Promise((success, failure) => { - resolve = success; - reject = failure; - }); - - annotationService.annotations = []; - annotationService.readFromMarker(resolve, reject, 2, 'a', 1); - return promise.catch((error) => { - expect(error.message).toEqual('Could not read annotations from file due to invalid or expired token'); - expect(annotationService.emit).toBeCalledWith('annotationerror', { - reason: 'authorization', - error: expect.any(String) - }); - }); - }); - }); - - describe('getReadUrl()', () => { - it('should return the original url if no limit or marker exists', () => { - annotationService.api = 'box'; - annotationService.fileId = 1; - const fileVersionId = 2; - const url = `${annotationService.api}/2.0/files/${ - annotationService.fileId - }/annotations?version=${fileVersionId}&fields=item,thread,details,message,created_by,created_at,modified_at,permissions`; - - const result = annotationService.getReadUrl(fileVersionId); - expect(result).toEqual(url); - }); - - it('should add a marker and limit if provided', () => { - annotationService.api = 'box'; - annotationService.fileId = 1; - const fileVersionId = 2; - const marker = 'next_annotation'; - const limit = 1; - const url = `${annotationService.api}/2.0/files/${ - annotationService.fileId - }/annotations?version=${fileVersionId}&fields=item,thread,details,message,created_by,created_at,modified_at,permissions&marker=${marker}&limit=${limit}`; - - const result = annotationService.getReadUrl(fileVersionId, marker, limit); - expect(result).toEqual(url); - }); - }); -}); diff --git a/src/__tests__/AnnotationThread-test.js b/src/__tests__/AnnotationThread-test.js index cd9e1a97b..d8ffa27e7 100644 --- a/src/__tests__/AnnotationThread-test.js +++ b/src/__tests__/AnnotationThread-test.js @@ -1,15 +1,12 @@ /* eslint-disable no-unused-expressions */ import AnnotationThread from '../AnnotationThread'; -import Annotation from '../Annotation'; import * as util from '../util'; import { STATES, TYPES, CLASS_ANNOTATION_POINT_MARKER, DATA_TYPE_ANNOTATION_INDICATOR, - CLASS_HIDDEN, - THREAD_EVENT, - SELECTOR_ANNOTATED_ELEMENT + THREAD_EVENT } from '../constants'; let thread; @@ -18,15 +15,21 @@ const html = '
'; describe('AnnotationThread', () => { let rootElement; + let api = { + user: { + id: '1' + } + }; + beforeEach(() => { rootElement = document.createElement('div'); rootElement.innerHTML = html; document.body.appendChild(rootElement); thread = new AnnotationThread({ - annotatedElement: document.querySelector(SELECTOR_ANNOTATED_ELEMENT), + annotatedElement: rootElement, annotations: [], - annotationService: { user: { id: '1' } }, + api, fileVersionId: '1', isMobile: false, location: {}, @@ -35,22 +38,8 @@ describe('AnnotationThread', () => { type: 'point' }); - thread.dialog = { - activateReply: jest.fn(), - addListener: jest.fn(), - addAnnotation: jest.fn(), - destroy: jest.fn(), - setup: jest.fn(), - removeAllListeners: jest.fn(), - show: jest.fn(), - hide: jest.fn(), - scrollToLastComment: jest.fn(), - removeAnnotation: jest.fn(), - enable: jest.fn(), - disable: jest.fn() - }; - thread.emit = jest.fn(); + util.shouldDisplayMobileUI = jest.fn().mockReturnValue(false); }); afterEach(() => { @@ -61,39 +50,32 @@ describe('AnnotationThread', () => { describe('destroy()', () => { beforeEach(() => { thread.state = STATES.pending; - thread.unbindCustomListenersOnDialog = jest.fn(); thread.unbindDOMListeners = jest.fn(); + thread.unmountPopover = jest.fn(); }); it('should unbind listeners and remove thread element and broadcast that the thread was deleted', () => { thread.destroy(); - expect(thread.unbindCustomListenersOnDialog).toBeCalled(); expect(thread.unbindDOMListeners).toBeCalled(); expect(thread.emit).not.toBeCalledWith(THREAD_EVENT.threadDelete); + expect(thread.unmountPopover).toBeCalled(); }); it('should emit annotationthreaddeleted only if thread is not in a pending state', () => { thread.state = STATES.inactive; thread.destroy(); - expect(thread.unbindCustomListenersOnDialog).toBeCalled(); expect(thread.unbindDOMListeners).toBeCalled(); expect(thread.emit).toBeCalledWith(THREAD_EVENT.threadDelete); - }); - - it('should not destroy the dialog on mobile', () => { - thread.element = null; - thread.isMobile = true; - - thread.destroy(); - expect(thread.unbindCustomListenersOnDialog).not.toBeCalled(); - expect(thread.dialog.destroy).not.toBeCalled(); + expect(thread.unmountPopover).toBeCalled(); }); }); describe('hide()', () => { it('should hide the thread element', () => { + thread.unmountPopover = jest.fn(); thread.hide(); - expect(thread.element.classList).toContain(CLASS_HIDDEN); + expect(thread.unmountPopover).toBeCalled(); + expect(thread.state).toEqual(STATES.inactive); }); }); @@ -104,162 +86,99 @@ describe('AnnotationThread', () => { }); }); - describe('isDialogVisible()', () => { - beforeEach(() => { - thread.dialog = { - element: document.createElement('div') - }; - }); - - it('returns true if thread\'s dialog is visible', () => { - expect(thread.isDialogVisible()).toBeTruthy(); - }); - - it('returns false if thread\'s dialog is hidden', () => { - thread.dialog.element.classList.add(CLASS_HIDDEN); - expect(thread.isDialogVisible()).toBeFalsy(); - }); - }); - - describe('showDialog()', () => { - it('should setup the thread dialog if the dialog element does not already exist', () => { - thread.dialog.element = null; - thread.showDialog(); - expect(thread.dialog.setup).toBeCalled(); - expect(thread.dialog.show).toBeCalled(); - }); - - it('should not setup the thread dialog if the dialog element already exists', () => { - thread.dialog.element = {}; - thread.showDialog(); - expect(thread.dialog.setup).not.toBeCalled(); - expect(thread.dialog.show).toBeCalled(); - }); - }); - - describe('hideDialog()', () => { - it('should hide the thread dialog', () => { - thread.hideDialog(); - expect(thread.state).toEqual(STATES.inactive); - expect(thread.dialog.hide).toBeCalled(); - }); - }); - - describe('saveAnnotation()', () => { + describe('save()', () => { beforeEach(() => { thread.getThreadEventData = jest.fn().mockReturnValue({}); - thread.annotationService.create = jest.fn(); thread.handleThreadSaveError = jest.fn(); thread.updateTemporaryAnnotation = jest.fn(); + thread.renderAnnotationPopover = jest.fn(); }); it('should save an annotation with the specified type and text', (done) => { - thread.annotationService.create = jest.fn().mockResolvedValue({}); + thread.api.create = jest.fn().mockResolvedValue({}); - const promise = thread.saveAnnotation('point', 'blah'); + const promise = thread.save('point', 'blah'); promise.then(() => { expect(thread.updateTemporaryAnnotation).toBeCalled(); done(); }); - expect(thread.annotationService.create).toBeCalled(); - expect(thread.dialog.disable).toBeCalled(); + expect(thread.api.create).toBeCalled(); }); it('should delete the temporary annotation and broadcast an error if there was an error saving', (done) => { - thread.annotationService.create = jest.fn().mockRejectedValue({}); + thread.api.create = jest.fn().mockRejectedValue({}); - const promise = thread.saveAnnotation('point', 'blah'); + const promise = thread.save('point', 'blah'); promise.then(() => { expect(thread.handleThreadSaveError).toBeCalled(); done(); }); - expect(thread.annotationService.create).toBeCalled(); + expect(thread.api.create).toBeCalled(); expect(thread.updateTemporaryAnnotation).not.toBeCalled(); - expect(thread.dialog.disable).toBeCalled(); }); }); describe('updateTemporaryAnnotation()', () => { + const tempAnnotation = { id: 1 }; + const serverAnnotation = { + id: 456, + threadNumber: 1, + message: 'comment' + }; + beforeEach(() => { - thread.annotationService.create = jest.fn(); - thread.saveAnnotationToThread = jest.fn(); + thread.api.create = jest.fn(); thread.getThreadEventData = jest.fn().mockReturnValue({}); + thread.renderAnnotationPopover = jest.fn(); + thread.comments = [tempAnnotation]; }); it('should save annotation to thread if it does not exist in annotations array', () => { - const serverAnnotation = 'real annotation'; - const tempAnnotation = serverAnnotation; - thread.updateTemporaryAnnotation(tempAnnotation, serverAnnotation); - expect(thread.saveAnnotationToThread).toBeCalled(); + thread.updateTemporaryAnnotation(tempAnnotation.id, serverAnnotation); + expect(thread.comments).toContain(serverAnnotation); }); it('should overwrite a local annotation to the thread if it does exist as an associated annotation', () => { - const serverAnnotation = { annotationID: 123 }; - const tempAnnotation = { annotationID: 1 }; - - thread.annotations[tempAnnotation.annotationID] = tempAnnotation; - expect(thread.annotations[123]).toBeUndefined(); - thread.updateTemporaryAnnotation(tempAnnotation, serverAnnotation); - expect(thread.saveAnnotationToThread).not.toBeCalled(); - expect(thread.annotations[123]).toStrictEqual(serverAnnotation); + thread.updateTemporaryAnnotation(tempAnnotation.id, serverAnnotation); + expect(thread.comments).not.toContain(tempAnnotation); + expect(thread.comments).toContain(serverAnnotation); }); it('should emit an annotationsaved event on success', () => { - const serverAnnotation = { threadNumber: 1 }; - const tempAnnotation = serverAnnotation; thread.threadNumber = undefined; - thread.emit = jest.fn(); - - thread.updateTemporaryAnnotation(tempAnnotation, serverAnnotation); + thread.updateTemporaryAnnotation(tempAnnotation.id, serverAnnotation); expect(thread.emit).toBeCalledWith(THREAD_EVENT.save); }); - it('should update thread number and replace temporary annotation if dialog exists', () => { - const serverAnnotation = { annotationID: 123 }; - const tempAnnotation = { annotationID: 1 }; - thread.threadNumber = 'something'; - thread.dialog.element = document.createElement('div'); - - thread.updateTemporaryAnnotation(tempAnnotation, serverAnnotation); - expect(thread.dialog.element.dataset.threadNumber).not.toBeUndefined(); - expect(thread.dialog.enable).toBeCalledWith(serverAnnotation.annotationID); - expect(thread.dialog.addAnnotation).toBeCalledWith(serverAnnotation); - expect(thread.dialog.removeAnnotation).toBeCalledWith(tempAnnotation.annotationID); - expect(thread.dialog.scrollToLastComment).toBeCalled(); + it('should only render popover on desktop', () => { + thread.updateTemporaryAnnotation(tempAnnotation.id, serverAnnotation); + expect(thread.renderAnnotationPopover).toBeCalled(); + expect(thread.state).toEqual(STATES.inactive); }); - it('should only show dialog immediately on mobile devices', () => { - const serverAnnotation = { threadNumber: 1 }; - const tempAnnotation = serverAnnotation; - thread.showDialog = jest.fn(); - - // Don't show dialog on web browsers - thread.updateTemporaryAnnotation(tempAnnotation, serverAnnotation); - expect(thread.showDialog).not.toBeCalled(); - expect(thread.state).not.toEqual(STATES.hover); - - // Only show dialog on mobile browsers - thread.isMobile = true; - thread.updateTemporaryAnnotation(tempAnnotation, serverAnnotation); - expect(thread.showDialog).toBeCalled(); - expect(thread.state).toEqual(STATES.hover); + it('should only render popover on mobile', () => { + util.shouldDisplayMobileUI = jest.fn().mockReturnValue(true); + thread.updateTemporaryAnnotation(tempAnnotation.id, serverAnnotation); + expect(thread.state).toEqual(STATES.active); + expect(thread.renderAnnotationPopover).toBeCalled(); }); }); - describe('deleteAnnotation()', () => { - let annotationService; + describe('delete()', () => { let annotation; let annotation2; const threadPromise = Promise.resolve(); beforeEach(() => { - annotationService = { - user: { id: 1 }, + api = { + user: { + id: 1 + }, delete: jest.fn().mockResolvedValue(threadPromise) }; annotation = { - annotationID: 'someID', + id: 'someID', permissions: { can_delete: true }, @@ -267,132 +186,85 @@ describe('AnnotationThread', () => { }; annotation2 = { - annotationID: 'someID2', + id: 'someID2', permissions: { can_delete: false }, threadID: 1 }; - thread = new AnnotationThread({ - annotatedElement: document.querySelector(SELECTOR_ANNOTATED_ELEMENT), - annotations: { someID: annotation }, - annotationService, - fileVersionId: '1', - isMobile: false, - location: {}, - threadID: '2', - threadNumber: '1', - type: 'point' - }); - - thread.dialog = { - addListener: jest.fn(), - addAnnotation: jest.fn(), - activateReply: jest.fn(), - destroy: jest.fn(), - removeAllListeners: jest.fn(), - show: jest.fn(), - hide: jest.fn(), - removeAnnotation: jest.fn(), - hideMobileDialog: jest.fn(), - setup: jest.fn() - }; - + thread.api = api; + thread.comments = [annotation]; util.isPlainHighlight = jest.fn(); - util.getFirstAnnotation = jest.fn().mockReturnValue(annotation); thread.cancelFirstComment = jest.fn(); thread.destroy = jest.fn(); - thread.showDialog = jest.fn(); + thread.renderAnnotationPopover = jest.fn(); thread.getThreadEventData = jest.fn().mockReturnValue({ threadNumber: 1 }); thread.emit = jest.fn(); }); - it('should destroy the thread if the deleted annotation was the last annotation in the thread', (done) => { - thread.isMobile = false; - util.getFirstAnnotation = jest.fn(); - - const promise = thread.deleteAnnotation('someID', false); + it('should destroy the thread if the deleted annotation was the last annotation in the thread', () => { + const promise = thread.delete('someID', false); promise.then(() => { threadPromise.then(() => { expect(thread.destroy).toBeCalled(); - expect(thread.dialog.removeAnnotation).not.toBeCalled(); - expect(thread.dialog.hideMobileDialog).not.toBeCalled(); - done(); + expect(thread.renderAnnotationPopover).not.toBeCalled(); }); }); }); - it('should destroy the thread and hide the mobile dialog if the deleted annotation was the last annotation in the thread on mobile', (done) => { - thread.isMobile = true; - util.getFirstAnnotation = jest.fn(); - - const promise = thread.deleteAnnotation('someID', false); - promise.then(() => { - expect(thread.dialog.removeAnnotation).toBeCalled(); - expect(thread.dialog.hideMobileDialog).toBeCalled(); - done(); - }); - }); - - it('should remove the relevant annotation from its dialog if the deleted annotation was not the last one', (done) => { - // Add another annotation to thread so 'someID' isn't the only annotation - thread.annotations[annotation2.annotationID] = annotation2; - - const promise = thread.deleteAnnotation('someID', false); + it('should remove the relevant annotation from its dialog if the deleted annotation was not the last one', () => { + thread.comments.push(annotation2); + const promise = thread.delete('someID', false); promise.then(() => { - expect(thread.dialog.removeAnnotation).toBeCalledWith('someID'); - expect(thread.dialog.activateReply).toBeCalled(); - done(); + expect(thread.renderAnnotationPopover).toBeCalled(); }); }); - it('should make a server call to delete an annotation with the specified ID if useServer is true', (done) => { - const promise = thread.deleteAnnotation('someID', true); + it('should make a server call to delete an annotation with the specified ID if useServer is true', () => { + thread.comments.push(annotation2); + const promise = thread.delete('someID', true); promise.then(() => { expect(thread.emit).not.toBeCalledWith(THREAD_EVENT.threadCleanup); - expect(annotationService.delete).toBeCalledWith('someID'); - done(); + expect(api.delete).toBeCalledWith('someID'); }); }); - it('should also delete blank highlight comment from the server when removing the last comment on a highlight thread', (done) => { + it('should also delete blank highlight comment from the server when removing the last comment on a highlight thread', () => { annotation2.permissions.can_delete = false; - thread.annotations[annotation2.annotationID] = annotation2; - util.isPlain = jest.fn().mockReturnValue(true); + thread.comments.push(annotation2); + util.isPlainHighlight = jest.fn().mockReturnValue(true); - const promise = thread.deleteAnnotation('someID', true); + const promise = thread.delete('someID', true); promise.then(() => { - expect(annotationService.delete).toBeCalledWith('someID'); - done(); + expect(api.delete).toBeCalledWith('someID'); }); }); - it('should not make a server call to delete an annotation with the specified ID if useServer is false', (done) => { - const promise = thread.deleteAnnotation('someID', false); + it('should not make a server call to delete an annotation with the specified ID if useServer is false', () => { + const promise = thread.delete('someID', false); promise.then(() => { - expect(annotationService.delete).not.toBeCalled(); - done(); + expect(api.delete).not.toBeCalled(); }); }); - it('should broadcast an error if there was an error deleting from server', (done) => { - annotationService.delete = jest.fn().mockRejectedValue(); + it('should broadcast an error if there was an error deleting from server', () => { + api.delete = jest.fn().mockRejectedValue(); + thread.api = api; - const promise = thread.deleteAnnotation('someID', true); + const promise = thread.delete('someID', true); promise.catch(() => { - expect(annotationService.delete).toBeCalled(); - done(); + expect(api.delete).toBeCalled(); }); }); it('should toggle highlight dialogs with the delete of the last comment if user does not have permission to delete the entire annotation', () => { - thread.annotations[annotation2.annotationID] = annotation2; - util.isPlain = jest.fn().mockReturnValue(true); + thread.comments.push(annotation2); + util.isPlainHighlight = jest.fn().mockReturnValue(true); - const promise = thread.deleteAnnotation('someID'); + const promise = thread.delete('someID'); promise.then(() => { expect(thread.cancelFirstComment).toBeCalled(); expect(thread.destroy).not.toBeCalled(); @@ -401,10 +273,10 @@ describe('AnnotationThread', () => { it('should destroy the annotation with the delete of the last comment if the user has permissions', () => { annotation2.permissions.can_delete = true; - thread.annotations[annotation2.annotationID] = annotation2; - util.isPlain = jest.fn().mockReturnValue(true); + thread.comments.push(annotation2); + util.isPlainHighlight = jest.fn().mockReturnValue(true); - const promise = thread.deleteAnnotation('someID'); + const promise = thread.delete('someID'); promise.then(() => { expect(thread.emit).toBeCalledWith(THREAD_EVENT.threadCleanup); expect(thread.emit).toBeCalledWith(THREAD_EVENT.delete); @@ -425,11 +297,15 @@ describe('AnnotationThread', () => { }); describe('scrollToPage()', () => { - it('should do nothing if annotation does not have a location or page', () => { - const pageEl = { + let pageEl; + beforeEach(() => { + pageEl = { scrollIntoView: jest.fn() }; + thread.getPopoverParent = jest.fn().mockReturnValue(pageEl); + }); + it('should do nothing if annotation does not have a location or page', () => { thread.location = {}; thread.scrollToPage(); @@ -439,12 +315,8 @@ describe('AnnotationThread', () => { }); it('should scroll annotation\'s page into view', () => { - thread.location = { page: 1 }; - const pageEl = { - scrollIntoView: jest.fn() - }; - thread.annotatedElement = { - querySelector: jest.fn().mockReturnValue(pageEl) + thread.location = { + page: 1 }; thread.scrollToPage(); expect(pageEl.scrollIntoView).toBeCalled(); @@ -503,42 +375,17 @@ describe('AnnotationThread', () => { describe('setup()', () => { beforeEach(() => { - thread.createDialog = jest.fn(); - thread.bindCustomListenersOnDialog = jest.fn(); thread.setupElement = jest.fn(); - thread.destroy = jest.fn(); - util.getFirstAnnotation = jest.fn().mockReturnValue({}); - }); - - it('should setup dialog', () => { - thread.dialog = {}; - thread.setup(); - expect(thread.createDialog).toBeCalled(); - expect(thread.bindCustomListenersOnDialog).toBeCalled(); - expect(thread.setupElement).toBeCalled(); - expect(thread.dialog.isMobile).toEqual(thread.isMobile); }); - it('should set state to pending if thread is initialized with no annotations', () => { - util.getFirstAnnotation = jest.fn().mockReturnValue(null); + it('should set state to pending for unsaved annotations', () => { + thread.threadNumber = undefined; thread.setup(); expect(thread.state).toEqual(STATES.pending); }); - it('should set state to inactive if thread is initialized with annotations', () => { - thread = new AnnotationThread({ - annotatedElement: document.querySelector(SELECTOR_ANNOTATED_ELEMENT), - annotations: [{}], - annotationService: {}, - fileVersionId: '1', - isMobile: false, - location: {}, - threadID: '2', - threadNumber: '1', - type: 'point' - }); - thread.destroy = jest.fn(); - + it('should set state to inactive for saved annotations', () => { + thread.threadNumber = 1; thread.setup(); expect(thread.state).toEqual(STATES.inactive); }); @@ -558,7 +405,6 @@ describe('AnnotationThread', () => { beforeEach(() => { thread.element = document.createElement('div'); thread.element.addEventListener = jest.fn(); - thread.isMobile = false; }); it('should bind DOM listeners', () => { @@ -567,7 +413,7 @@ describe('AnnotationThread', () => { }); it('should not add mouseleave listener for mobile browsers', () => { - thread.isMobile = true; + util.shouldDisplayMobileUI = jest.fn().mockReturnValue(true); thread.bindDOMListeners(); expect(thread.element.addEventListener).toBeCalledWith('click', expect.any(Function)); }); @@ -577,7 +423,6 @@ describe('AnnotationThread', () => { beforeEach(() => { thread.element = document.createElement('div'); thread.element.removeEventListener = jest.fn(); - thread.isMobile = false; }); it('should unbind DOM listeners', () => { @@ -586,62 +431,40 @@ describe('AnnotationThread', () => { }); it('should not add mouseleave listener for mobile browsers', () => { - thread.isMobile = true; + util.shouldDisplayMobileUI = jest.fn().mockReturnValue(true); thread.unbindDOMListeners(); expect(thread.element.removeEventListener).toBeCalledWith('click', expect.any(Function)); }); }); - describe('bindCustomListenersOnDialog()', () => { - it('should bind custom listeners on dialog', () => { - thread.bindCustomListenersOnDialog(); - expect(thread.dialog.addListener).toBeCalledWith('annotationcreate', expect.any(Function)); - expect(thread.dialog.addListener).toBeCalledWith('annotationcancel', expect.any(Function)); - expect(thread.dialog.addListener).toBeCalledWith('annotationdelete', expect.any(Function)); - expect(thread.dialog.addListener).toBeCalledWith('annotationshow', expect.any(Function)); - expect(thread.dialog.addListener).toBeCalledWith('annotationhide', expect.any(Function)); - }); - }); - - describe('unbindCustomListenersOnDialog()', () => { - it('should unbind custom listeners from dialog', () => { - thread.unbindCustomListenersOnDialog(); - expect(thread.dialog.removeAllListeners).toBeCalledWith([ - 'annotationcreate', - 'annotationcancel', - 'annotationdelete', - 'annotationshow', - 'annotationhide' - ]); - }); - }); - describe('cancelUnsavedAnnotation()', () => { beforeEach(() => { thread.destroy = jest.fn(); - thread.hideDialog = jest.fn(); + thread.unmountPopover = jest.fn(); }); - it('should destroy thread if in a pending/pending-active state', () => { - util.isPending = jest.fn().mockReturnValue(true); + it('should destroy thread if in a pending state', () => { + thread.state = STATES.pending; thread.cancelUnsavedAnnotation(); expect(thread.destroy).toBeCalled(); expect(thread.emit).toBeCalledWith(THREAD_EVENT.cancel); - expect(thread.hideDialog).not.toBeCalled(); + expect(thread.unmountPopover).not.toBeCalled(); }); - it('should not destroy thread if not in a pending/pending-active state', () => { - util.isPending = jest.fn().mockReturnValue(false); + it('should not destroy thread if not in a pending state', () => { + thread.state = STATES.inactive; thread.cancelUnsavedAnnotation(); expect(thread.destroy).not.toBeCalled(); expect(thread.emit).not.toBeCalledWith(THREAD_EVENT.cancel); - expect(thread.hideDialog).toBeCalled(); + expect(thread.unmountPopover).toBeCalled(); }); }); describe('getThreadEventData()', () => { it('should return thread type and threadID', () => { - thread.annotationService.user = { id: -1 }; + thread.api.user = { + id: -1 + }; thread.threadNumber = undefined; const data = thread.getThreadEventData(); expect(data).toStrictEqual({ @@ -651,7 +474,9 @@ describe('AnnotationThread', () => { }); it('should also return annotator\'s user id', () => { - thread.annotationService.user = { id: 1 }; + thread.api.user = { + id: 1 + }; thread.threadNumber = undefined; const data = thread.getThreadEventData(); expect(data).toStrictEqual({ @@ -662,7 +487,9 @@ describe('AnnotationThread', () => { }); it('should return thread type and threadID', () => { - thread.annotationService.user = { id: -1 }; + thread.api.user = { + id: -1 + }; thread.threadNumber = 1; const data = thread.getThreadEventData(); expect(data).toStrictEqual({ @@ -681,65 +508,11 @@ describe('AnnotationThread', () => { }); }); - describe('saveAnnotationToThread()', () => { - it('should add the annotation to the thread, and add to the dialog when the dialog exists', () => { - thread.annotations.push = jest.fn(); - const annotation = new Annotation({ - fileVersionId: '2', - threadID: '1', - type: 'point', - text: 'blah', - threadNumber: '1', - location: { x: 0, y: 0 }, - created: Date.now() - }); - - thread.saveAnnotationToThread(annotation); - expect(thread.annotations[annotation.annotationID]).not.toBeUndefined(); - expect(thread.dialog.activateReply).toBeCalled(); - expect(thread.dialog.addAnnotation).toBeCalledWith(annotation); - }); - - it('should not try to push an annotation to the dialog if it doesn\'t exist', () => { - const annotation = new Annotation({ - fileVersionId: '2', - threadID: '1', - type: 'point', - text: 'blah', - threadNumber: '1', - location: { x: 0, y: 0 }, - created: Date.now() - }); - - thread.dialog = undefined; - thread.saveAnnotationToThread(annotation); - expect(thread.annotations[annotation.annotationID]).not.toBeUndefined(); - }); - }); - - describe('createAnnotationDialog()', () => { - it('should correctly create the annotation data object', () => { - const annotationData = thread.createAnnotationData('highlight', 'test'); - expect(annotationData.location).toEqual(thread.location); - expect(annotationData.fileVersionId).toEqual(thread.fileVersionId); - expect(annotationData.thread).toEqual(thread.thread); - expect(annotationData.user.id).toEqual('1'); - }); - }); - describe('createAnnotation()', () => { it('should create a new point annotation', () => { - thread.saveAnnotation = jest.fn(); - thread.createAnnotation({ text: 'bleh' }); - expect(thread.saveAnnotation).toBeCalledWith(TYPES.point, 'bleh'); - }); - }); - - describe('deleteAnnotationWithID()', () => { - it('should delete a point annotation with the matching annotationID', () => { - thread.deleteAnnotation = jest.fn(); - thread.deleteAnnotationWithID({ annotationID: 1 }); - expect(thread.deleteAnnotation).toBeCalledWith(1); + thread.save = jest.fn(); + thread.createAnnotation('bleh'); + expect(thread.save).toBeCalledWith(TYPES.point, 'bleh'); }); }); @@ -751,10 +524,14 @@ describe('AnnotationThread', () => { thread.location = {}; thread.regenerateBoundary(); - thread.location = { x: 'something' }; + thread.location = { + x: 'something' + }; thread.regenerateBoundary(); - thread.location = { y: 'something' }; + thread.location = { + y: 'something' + }; thread.regenerateBoundary(); expect(thread.minX).toBeUndefined(); @@ -762,7 +539,10 @@ describe('AnnotationThread', () => { }); it('should set the min/max x/y values to the thread location', () => { - thread.location = { x: 1, y: 2 }; + thread.location = { + x: 1, + y: 2 + }; thread.regenerateBoundary(); expect(thread.minX).toEqual(1); expect(thread.minY).toEqual(2); @@ -773,9 +553,9 @@ describe('AnnotationThread', () => { describe('handleThreadSaveError()', () => { it('should delete temp annotation and emit event', () => { - thread.deleteAnnotation = jest.fn(); + thread.delete = jest.fn(); thread.handleThreadSaveError(new Error(), 1); - expect(thread.deleteAnnotation).toBeCalledWith(1, false); + expect(thread.delete).toBeCalledWith({ id: 1 }, false); expect(thread.emit).toBeCalledWith(THREAD_EVENT.createError); }); }); diff --git a/src/__tests__/Annotator-test.js b/src/__tests__/Annotator-test.js index 8d8104a37..5a6053366 100644 --- a/src/__tests__/Annotator-test.js +++ b/src/__tests__/Annotator-test.js @@ -1,6 +1,5 @@ /* eslint-disable no-unused-expressions */ import Annotator from '../Annotator'; -import * as util from '../util'; import { STATES, TYPES, @@ -10,33 +9,38 @@ import { SELECTOR_ANNOTATED_ELEMENT, SELECTOR_BOX_PREVIEW_HEADER_CONTAINER } from '../constants'; +import AnnotationThread from '../AnnotationThread'; +import FileVersionAPI from '../api/FileVersionAPI'; +import AnnotationModeController from '../controllers/AnnotationModeController'; -let annotator; -let controller; -let thread; -const html = `
- -
`; +jest.mock('../AnnotationThread'); +jest.mock('../api/FileVersionAPI'); +jest.mock('../controllers/AnnotationModeController'); describe('Annotator', () => { let rootElement; + let annotator; + let controller; + let thread; + let api; + const html = ` +
`; beforeEach(() => { rootElement = document.createElement('div'); rootElement.innerHTML = html; document.body.appendChild(rootElement); - controller = { - init: jest.fn(), - addListener: jest.fn(), - registerThread: jest.fn(), - isEnabled: jest.fn(), - getButton: jest.fn(), - enter: jest.fn(), - exit: jest.fn(), - setupSharedDialog: jest.fn(), - getThreadByID: jest.fn() - }; + thread = new AnnotationThread(); + thread.threadID = '123abc'; + thread.location = { page: 1 }; + thread.type = 'something'; + thread.annotations = []; + + controller = new AnnotationModeController(); + controller.registerThread = jest.fn().mockReturnValue(thread); + + api = new FileVersionAPI(); const options = { annotator: { @@ -47,9 +51,8 @@ describe('Annotator', () => { }; annotator = new Annotator({ - canAnnotate: true, - container: document, - annotationService: {}, + container: rootElement, + api, file: { file_version: { id: 1 } }, @@ -64,20 +67,6 @@ describe('Annotator', () => { authError: 'auth error' } }); - - thread = { - threadID: '123abc', - show: jest.fn(), - hide: jest.fn(), - addListener: jest.fn(), - unbindCustomListenersOnThread: jest.fn(), - removeListener: jest.fn(), - scrollIntoView: jest.fn(), - getThreadEventData: jest.fn(), - showDialog: jest.fn(), - type: 'something', - location: { page: 1 } - }; }); afterEach(() => { @@ -100,14 +89,12 @@ describe('Annotator', () => { annotator.setScale = jest.fn(); annotator.setupAnnotations = jest.fn(); annotator.loadAnnotations = jest.fn(); - annotator.setupMobileDialog = jest.fn(); annotator.getAnnotationPermissions = jest.fn(); - annotator.permissions = { canAnnotate: true }; + annotator.permissions = { can_annotate: true }; }); it('should set scale and setup annotations', () => { - annotator.isMobile = false; annotator.init(5); expect(annotator.setScale).toBeCalledWith(5); expect(annotator.setupAnnotations).toBeCalled(); @@ -119,55 +106,6 @@ describe('Annotator', () => { annotator.init(5); expect(annotator.headerElement).toEqual(document.querySelector(SELECTOR_BOX_PREVIEW_HEADER_CONTAINER)); }); - - it('should setup mobile dialog for mobile browsers', () => { - annotator.isMobile = true; - annotator.init(); - expect(annotator.setupMobileDialog).toBeCalled(); - }); - }); - - describe('setupMobileDialog()', () => { - it('should generate mobile annotations dialog and append to container', () => { - annotator.container = { - appendChild: jest.fn() - }; - annotator.setupMobileDialog(); - expect(annotator.container.appendChild).toBeCalled(); - expect(annotator.mobileDialogEl.children.length).toEqual(1); - }); - }); - - describe('removeThreadFromSharedDialog()', () => { - beforeEach(() => { - util.hideElement = jest.fn(); - util.showElement = jest.fn(); - }); - - it('should do nothing if the mobile dialog does not exist or is hidden', () => { - annotator.removeThreadFromSharedDialog(); - expect(util.hideElement).not.toBeCalled(); - - annotator.mobileDialogEl = { - classList: { - contains: jest.fn().mockReturnValue(true) - }, - removeChild: jest.fn(), - lastChild: {} - }; - annotator.removeThreadFromSharedDialog(); - expect(util.hideElement).not.toBeCalled(); - }); - - it('should generate mobile annotations dialog and append to container', () => { - annotator.mobileDialogEl = document.createElement('div'); - annotator.mobileDialogEl.appendChild(document.createElement('div')); - - annotator.removeThreadFromSharedDialog(); - expect(util.hideElement).toBeCalled(); - expect(util.showElement).toBeCalled(); - expect(annotator.mobileDialogEl.children.length).toEqual(0); - }); }); describe('loadAnnotations()', () => { @@ -201,16 +139,15 @@ describe('Annotator', () => { describe('setupAnnotations()', () => { it('should initialize thread map and bind DOM listeners', () => { annotator.bindDOMListeners = jest.fn(); - annotator.bindCustomListenersOnService = jest.fn(); + annotator.bindCustomListeners = jest.fn(); annotator.addListener = jest.fn(); annotator.setupControllers = jest.fn(); annotator.setupAnnotations(); expect(annotator.bindDOMListeners).toBeCalled(); - expect(annotator.bindCustomListenersOnService).toBeCalled(); + expect(annotator.bindCustomListeners).toBeCalled(); expect(annotator.setupControllers).toBeCalled(); - expect(annotator.addListener).toBeCalledWith(ANNOTATOR_EVENT.scale, expect.any(Function)); }); }); @@ -223,19 +160,6 @@ describe('Annotator', () => { expect(controller.init).toBeCalled(); expect(controller.addListener).toBeCalledWith('annotationcontrollerevent', expect.any(Function)); }); - - it('should setup shared point dialog in the point controller', () => { - annotator.modeControllers = { point: controller }; - annotator.isMobile = true; - - annotator.setupControllers(); - expect(controller.init).toBeCalled(); - expect(controller.setupSharedDialog).toBeCalledWith(annotator.container, { - isMobile: annotator.isMobile, - hasTouch: annotator.hasTouch, - localized: annotator.localized - }); - }); }); describe('once annotator is initialized', () => { @@ -252,14 +176,13 @@ describe('Annotator', () => { describe('destroy()', () => { it('should unbind custom listeners on thread and unbind DOM listeners', () => { annotator.unbindDOMListeners = jest.fn(); - annotator.unbindCustomListenersOnService = jest.fn(); + annotator.unbindCustomListeners = jest.fn(); annotator.removeListener = jest.fn(); annotator.destroy(); expect(annotator.unbindDOMListeners).toBeCalled(); - expect(annotator.unbindCustomListenersOnService).toBeCalled(); - expect(annotator.removeListener).toBeCalledWith(ANNOTATOR_EVENT.scale, expect.any(Function)); + expect(annotator.unbindCustomListeners).toBeCalled(); }); }); @@ -306,9 +229,9 @@ describe('Annotator', () => { } }; const permissions = annotator.getAnnotationPermissions(file); - expect(permissions.canAnnotate).toBeFalsy(); - expect(permissions.canViewOwnAnnotations).toBeTruthy(); - expect(permissions.canViewAllAnnotations).toBeFalsy(); + expect(permissions.can_annotate).toBeFalsy(); + expect(permissions.can_view_annotations_self).toBeTruthy(); + expect(permissions.can_view_annotations_all).toBeFalsy(); }); }); @@ -328,33 +251,35 @@ describe('Annotator', () => { const threadPromise = Promise.resolve(threadMap); beforeEach(() => { - annotator.annotationService.getThreadMap = jest.fn(); + annotator.api.getThreadMap = jest.fn(); annotator.permissions = { - canViewAllAnnotations: true, - canViewOwnAnnotations: true + can_view_annotations_all: true, + can_view_annotations_self: true }; annotator.emit = jest.fn(); }); it('should not fetch existing annotations if the user does not have correct permissions', () => { annotator.permissions = { - canViewAllAnnotations: false, - canViewOwnAnnotations: false + can_view_annotations_all: false, + can_view_annotations_self: false }; const result = annotator.fetchAnnotations(); result.then(() => { expect(result).toBeTruthy(); - expect(annotator.annotationService.getThreadMap).not.toBeCalled(); + expect(annotator.api.getThreadMap).not.toBeCalled(); }); }); it('should fetch existing annotations if the user can view all annotations', () => { - annotator.annotationService.getThreadMap = jest.fn().mockReturnValue(threadPromise); + // api.getThreadMap = jest.fn().mockReturnValue(threadPromise); + api.fetchVersionAnnotations = jest.fn().mockResolvedValue({}); + annotator.api = api; annotator.permissions = { - canViewAllAnnotations: false, - canViewOwnAnnotations: true + can_view_annotations_all: false, + can_view_annotations_self: true }; const result = annotator.fetchAnnotations(); @@ -366,10 +291,12 @@ describe('Annotator', () => { }); it('should fetch existing annotations if the user can view all annotations', () => { - annotator.annotationService.getThreadMap = jest.fn().mockReturnValue(threadPromise); + // api.getThreadMap = jest.fn().mockReturnValue(threadPromise); + api.fetchVersionAnnotations = jest.fn().mockResolvedValue({}); + annotator.api = api; annotator.permissions = { - canViewAllAnnotations: true, - canViewOwnAnnotations: false + can_view_annotations_all: true, + can_view_annotations_self: false }; const result = annotator.fetchAnnotations(); @@ -383,54 +310,32 @@ describe('Annotator', () => { }); }); - describe('generateThreadMap()', () => { - const threadMap = { '123abc': thread }; + describe('generateAnnotationMap()', () => { + let threadMap; beforeEach(() => { - const annotation = { location: {}, type: 'highlight' }; - const lastAnnotation = { location: {}, type: 'highlight-comment' }; - util.getFirstAnnotation = jest.fn().mockReturnValue(annotation); - util.getLastAnnotation = jest.fn().mockReturnValue(lastAnnotation); - annotator.createAnnotationThread = jest.fn(); + annotator.options = { annotator: {} }; + threadMap = { '123abc': { type: 'highlight-comment', location: {} } }; }); it('should do nothing if annotator conf does not exist in options', () => { annotator.options = {}; - annotator.generateThreadMap(threadMap); - expect(annotator.createAnnotationThread).not.toBeCalled(); - }); - - it('should reset and create a new thread map by from annotations fetched from server', () => { - annotator.options.annotator = { NAME: 'name', TYPE: ['highlight-comment'] }; - annotator.createAnnotationThread = jest.fn().mockReturnValue(thread); - annotator.generateThreadMap(threadMap); - expect(annotator.createAnnotationThread).toBeCalled(); + annotator.generateAnnotationMap(threadMap); + expect(controller.registerThread).not.toBeCalled(); }); it('should register thread if controller exists', () => { - annotator.options.annotator = { NAME: 'name', TYPE: ['highlight-comment'] }; - annotator.modeControllers['highlight-comment'] = controller; - annotator.createAnnotationThread = jest.fn().mockReturnValue(thread); - annotator.generateThreadMap(threadMap); + annotator.modeControllers = { 'highlight-comment': controller }; + annotator.generateAnnotationMap(threadMap); expect(controller.registerThread).toBeCalled(); }); - - it('should not register a highlight comment thread with a plain highlight for the first annotation', () => { - annotator.options.annotator = { NAME: 'name', TYPE: ['highlight'] }; - annotator.modeControllers['highlight-comment'] = controller; - annotator.generateThreadMap(threadMap); - expect(controller.registerThread).not.toBeCalled(); - }); }); - describe('bindCustomListenersOnService()', () => { + describe('bindCustomListeners()', () => { it('should add an event listener', () => { - annotator.annotationService.addListener = jest.fn(); - annotator.bindCustomListenersOnService(); - expect(annotator.annotationService.addListener).toBeCalledWith( - ANNOTATOR_EVENT.error, - expect.any(Function) - ); + annotator.api.addListener = jest.fn(); + annotator.bindCustomListeners(); + expect(annotator.api.addListener).toBeCalledWith(ANNOTATOR_EVENT.error, expect.any(Function)); }); }); @@ -439,31 +344,9 @@ describe('Annotator', () => { annotator.emit = jest.fn(); }); - it('should emit annotatorerror on read error event', () => { - annotator.handleServicesErrors({ reason: 'read' }); - expect(annotator.emit).toBeCalledWith(ANNOTATOR_EVENT.error, expect.any(String)); - }); - - it('should emit annotatorerror and show annotations on create error event', () => { - annotator.handleServicesErrors({ reason: 'create' }); - expect(annotator.emit).toBeCalledWith(ANNOTATOR_EVENT.error, expect.any(String)); - expect(annotator.loadAnnotations).toBeCalled(); - }); - - it('should emit annotatorerror and show annotations on delete error event', () => { - annotator.handleServicesErrors({ reason: 'delete' }); - expect(annotator.emit).toBeCalledWith(ANNOTATOR_EVENT.error, expect.any(String)); - expect(annotator.loadAnnotations).toBeCalled(); - }); - - it('should emit annotatorerror on authorization error event', () => { - annotator.handleServicesErrors({ reason: 'authorization' }); - expect(annotator.emit).toBeCalledWith(ANNOTATOR_EVENT.error, expect.any(String)); - }); - - it('should not emit annotatorerror when event does not match', () => { - annotator.handleServicesErrors({ reason: 'no match' }); - expect(annotator.emit).not.toBeCalled(); + it('should emit annotatorerror on error event', () => { + annotator.handleServicesErrors({ error: {} }); + expect(annotator.emit).toBeCalledWith(ANNOTATOR_EVENT.error, annotator.localized.loadError); }); }); @@ -475,13 +358,6 @@ describe('Annotator', () => { annotator.emit = jest.fn(); }); - it('should reset mobile annotation dialog on resetMobileDialog', () => { - annotator.removeThreadFromSharedDialog = jest.fn(); - data.event = CONTROLLER_EVENT.resetMobileDialog; - annotator.handleControllerEvents(data); - expect(annotator.removeThreadFromSharedDialog).toBeCalled(); - }); - it('should toggle annotation mode on togglemode', () => { annotator.toggleAnnotationMode = jest.fn(); data.event = CONTROLLER_EVENT.toggleMode; @@ -513,11 +389,11 @@ describe('Annotator', () => { }); }); - describe('unbindCustomListenersOnService()', () => { + describe('unbindCustomListeners()', () => { it('should remove an event listener', () => { - annotator.annotationService.removeListener = jest.fn(); - annotator.unbindCustomListenersOnService(); - expect(annotator.annotationService.removeListener).toBeCalled(); + annotator.api.removeListener = jest.fn(); + annotator.unbindCustomListeners(); + expect(annotator.api.removeListener).toBeCalled(); }); }); @@ -544,11 +420,6 @@ describe('Annotator', () => { beforeEach(() => { annotator.getLocationFromEvent = jest.fn().mockReturnValue({ page: 1 }); annotator.emit = jest.fn(); - thread.dialog = { - postAnnotation: jest.fn(), - hasComments: false - }; - annotator.modeControllers = { point: controller }; @@ -604,6 +475,8 @@ describe('Annotator', () => { it('should create a point annotation thread using lastPointEvent', () => { thread.getThreadEventData = jest.fn().mockReturnValue({}); controller.getThreadByID = jest.fn().mockReturnValue(thread); + thread.renderAnnotationPopover = jest.fn(); + thread.save = jest.fn(); const result = annotator.createPointThread({ lastPointEvent: {}, @@ -611,12 +484,11 @@ describe('Annotator', () => { commentText: 'text' }); - expect(thread.dialog.hasComments).toBeTruthy(); - expect(thread.state).toEqual(STATES.hover); - expect(thread.dialog.postAnnotation).toBeCalledWith('text'); + expect(thread.state).toEqual(STATES.active); + expect(thread.save).toBeCalledWith(TYPES.point, 'text'); expect(annotator.emit).toBeCalledWith(THREAD_EVENT.threadSave, expect.any(Object)); expect(result).not.toBeNull(); - expect(thread.showDialog).toBeCalled(); + expect(thread.renderAnnotationPopover).toBeCalled(); }); }); diff --git a/src/__tests__/CommentBox-test.js b/src/__tests__/CommentBox-test.js deleted file mode 100644 index 2e822ea48..000000000 --- a/src/__tests__/CommentBox-test.js +++ /dev/null @@ -1,321 +0,0 @@ -/* eslint-disable no-unused-expressions */ -import CommentBox from '../CommentBox'; -import * as util from '../util'; -import { - CLASS_HIDDEN, - SELECTOR_ANNOTATION_BUTTON_CANCEL, - SELECTOR_ANNOTATION_BUTTON_POST, - CLASS_ANNOTATION_BUTTON_CANCEL, - CLASS_ANNOTATION_BUTTON_POST, - CLASS_ANNOTATION_TEXTAREA, - CLASS_INVALID_INPUT -} from '../constants'; - -describe('CommentBox', () => { - let commentBox; - let parentEl; - - beforeEach(() => { - parentEl = document.createElement('span'); - commentBox = new CommentBox(parentEl, { - localized: { - cancelButton: 'cancel' - } - }); - }); - - afterEach(() => { - commentBox.destroy(); - commentBox = null; - parentEl = null; - }); - - describe('constructor()', () => { - let tempCommentBox; - const localized = { - cancelButton: 'cancel', - postButton: 'post', - addCommentPlaceholder: 'placeholder' - }; - - beforeEach(() => { - tempCommentBox = new CommentBox(parentEl, { localized }); - }); - - afterEach(() => { - tempCommentBox.destroy(); - tempCommentBox = null; - }); - - it('should assign the parentEl to the container passed in', () => { - expect(tempCommentBox.parentEl).toStrictEqual(parentEl); - }); - - it('should assign cancelText to the string passed in the config', () => { - expect(tempCommentBox.cancelText).toEqual(localized.cancelButton); - }); - - it('should assign postText to the string passed in the config', () => { - expect(tempCommentBox.postText).toEqual(localized.postButton); - }); - - it('should assign placeholderText to the string passed in the config', () => { - expect(tempCommentBox.placeholderText).toEqual(localized.addCommentPlaceholder); - }); - }); - - describe('focus()', () => { - beforeEach(() => { - commentBox.textAreaEl = document.createElement('textarea'); - commentBox.textAreaEl.focus = jest.fn(); - }); - - it('should focus on the text area contained by the comment box', () => { - commentBox.focus(); - expect(commentBox.textAreaEl.focus).toBeCalled(); - }); - }); - - describe('clear()', () => { - it('should overwrite the text area\'s value with an empty string', () => { - commentBox.textAreaEl = document.createElement('textarea'); - commentBox.textAreaEl.value = 'yay'; - - commentBox.clear(); - expect(commentBox.textAreaEl.value).toEqual(''); - }); - }); - - describe('hide()', () => { - it('should do nothing if the comment box HTML doesn\'t exist', () => { - util.hideElement = jest.fn(); - commentBox.containerEl = null; - commentBox.hide(); - expect(util.hideElement).not.toBeCalled(); - }); - - it('should add the hidden class to the comment box element', () => { - util.hideElement = jest.fn(); - commentBox.containerEl = document.createElement('div'); - commentBox.hide(); - expect(util.hideElement).toBeCalled(); - }); - }); - - describe('show()', () => { - it('should invoke createComment box, if UI has not been created', () => { - commentBox.containerEl = null; - - commentBox.createCommentBox = jest.fn().mockReturnValue(document.createElement('div')); - commentBox.parentEl = document.createElement('div'); - util.focusTextArea = jest.fn(); - util.showElement = jest.fn(); - - commentBox.show(); - expect(commentBox.createCommentBox).toBeCalled(); - expect(util.showElement).toBeCalled(); - - // Nullify to prevent fail during destroy - commentBox.containerEl = null; - }); - - it('should remove the hidden class from the container', () => { - commentBox.show(); - expect(commentBox.containerEl.classList.contains(CLASS_HIDDEN)).toBeFalsy(); - expect(util.focusTextArea).toBeCalledWith(commentBox.textAreaEl); - }); - }); - - describe('destroy()', () => { - beforeEach(() => { - commentBox.containerEl = document.createElement('div'); - - commentBox.cancelEl = document.createElement('div'); - commentBox.cancelEl.classList.add(CLASS_ANNOTATION_BUTTON_CANCEL); - commentBox.cancelEl.removeEventListener = jest.fn(); - - commentBox.postEl = document.createElement('div'); - commentBox.postEl.classList.add(CLASS_ANNOTATION_BUTTON_POST); - commentBox.postEl.removeEventListener = jest.fn(); - - commentBox.textAreaEl = document.createElement('div'); - commentBox.textAreaEl.classList.add(CLASS_ANNOTATION_TEXTAREA); - commentBox.textAreaEl.removeEventListener = jest.fn(); - }); - - it('should do nothing if it\'s UI has not been created', () => { - commentBox.containerEl = undefined; - const unchanged = 'not even the right kind of data'; - commentBox.parentEl = unchanged; - commentBox.destroy(); - expect(commentBox.parentEl).toEqual(unchanged); - }); - - it('should remove event listeners', () => { - commentBox.destroy(); - expect(commentBox.cancelEl.removeEventListener).toBeCalled(); - expect(commentBox.postEl.removeEventListener).toBeCalled(); - expect(commentBox.textAreaEl.removeEventListener).toBeCalled(); - }); - }); - - describe('createHTML()', () => { - let el; - beforeEach(() => { - el = commentBox.createHTML(); - }); - - it('should create and return a section element with ba-create-highlight-comment class on it', () => { - expect(el.nodeName).toEqual('SECTION'); - expect(el.classList.contains('ba-create-comment')).toBeTruthy(); - }); - - it('should create a text area with the provided placeholder text', () => { - expect(el.querySelector('textarea')).not.toBeUndefined(); - }); - - it('should create a cancel button with the provided cancel text', () => { - expect(el.querySelector(SELECTOR_ANNOTATION_BUTTON_CANCEL)).not.toBeUndefined(); - }); - - it('should create a post button with the provided text', () => { - expect(el.querySelector(SELECTOR_ANNOTATION_BUTTON_POST)).not.toBeUndefined(); - }); - }); - - describe('onCancel()', () => { - beforeEach(() => { - commentBox.preventDefaultAndPropagation = jest.fn(); - commentBox.emit = jest.fn(); - commentBox.clear = jest.fn(); - }); - - it('should invoke clear()', () => { - commentBox.onCancel({ preventDefault: jest.fn() }); - expect(commentBox.clear).toBeCalled(); - }); - - it('should emit a cancel event', () => { - commentBox.onCancel({ preventDefault: jest.fn() }); - expect(commentBox.emit).toBeCalledWith(CommentBox.CommentEvents.cancel); - }); - }); - - describe('onPost()', () => { - beforeEach(() => { - commentBox.textAreaEl = document.createElement('textarea'); - commentBox.preventDefaultAndPropagation = jest.fn(); - commentBox.emit = jest.fn(); - commentBox.clear = jest.fn(); - }); - - it('should invalidate textarea and do nothing if textarea is blank', () => { - const text = ''; - commentBox.onPost({ preventDefault: jest.fn() }); - expect(commentBox.emit).not.toBeCalledWith(CommentBox.CommentEvents.post, text); - expect(commentBox.textAreaEl.classList).toContain(CLASS_INVALID_INPUT); - }); - - it('should emit a post event with the value of the text box', () => { - const text = 'a comment'; - commentBox.textAreaEl.value = text; - commentBox.onPost({ preventDefault: jest.fn() }); - expect(commentBox.emit).toBeCalledWith(CommentBox.CommentEvents.post, text); - }); - - it('should invoke clear()', () => { - commentBox.onCancel({ preventDefault: jest.fn() }); - expect(commentBox.clear).toBeCalled(); - }); - }); - - describe('createCommentBox()', () => { - beforeEach(() => { - const el = document.createElement('section'); - el.addEventListener = jest.fn(); - - const cancelEl = document.createElement('div'); - cancelEl.classList.add(CLASS_ANNOTATION_BUTTON_CANCEL); - cancelEl.addEventListener = jest.fn(); - el.appendChild(cancelEl); - - const postEl = document.createElement('div'); - postEl.classList.add(CLASS_ANNOTATION_BUTTON_POST); - postEl.addEventListener = jest.fn(); - el.appendChild(postEl); - - const textAreaEl = document.createElement('div'); - textAreaEl.classList.add(CLASS_ANNOTATION_TEXTAREA); - textAreaEl.addEventListener = jest.fn(); - el.appendChild(textAreaEl); - - commentBox.createHTML = jest.fn().mockReturnValue(el); - }); - - it('should create and return an HTML element for the UI', () => { - const el = commentBox.createCommentBox(); - expect(el.nodeName).not.toBeUndefined(); - }); - - it('should create a reference to the text area', () => { - commentBox.createCommentBox(); - expect(commentBox.textAreaEl).not.toBeUndefined(); - }); - - it('should create a reference to the cancel button', () => { - commentBox.createCommentBox(); - expect(commentBox.cancelEl).not.toBeUndefined(); - }); - - it('should create a reference to the post button', () => { - commentBox.createCommentBox(); - expect(commentBox.postEl).not.toBeUndefined(); - }); - - it('should add an event listener on the textarea, cancel and post buttons for desktop devices', () => { - const containerEl = commentBox.createCommentBox(); - expect(containerEl.addEventListener).not.toBeCalledWith('touchend', expect.any(Function)); - expect(commentBox.postEl.addEventListener).not.toBeCalledWith('touchend', expect.any(Function)); - expect(commentBox.cancelEl.addEventListener).not.toBeCalledWith('touchend', expect.any(Function)); - - expect(containerEl.addEventListener).toBeCalledWith('click', expect.any(Function)); - expect(commentBox.cancelEl.addEventListener).toBeCalledWith('click', commentBox.onCancel); - expect(commentBox.postEl.addEventListener).toBeCalledWith('click', commentBox.onPost); - expect(commentBox.textAreaEl.addEventListener).toBeCalledWith('focus', commentBox.focus); - }); - - it('should add an event listener on the textarea, cancel and post buttons if the user is on a touch-enabled non-mobile device', () => { - commentBox.hasTouch = true; - - const containerEl = commentBox.createCommentBox(); - - expect(containerEl.addEventListener).toBeCalledWith('touchend', expect.any(Function)); - expect(commentBox.postEl.addEventListener).toBeCalledWith('touchend', expect.any(Function)); - expect(commentBox.cancelEl.addEventListener).toBeCalledWith('touchend', expect.any(Function)); - expect(containerEl.addEventListener).toBeCalledWith('click', expect.any(Function)); - - expect(commentBox.cancelEl.addEventListener).toBeCalledWith('click', commentBox.onCancel); - expect(commentBox.postEl.addEventListener).toBeCalledWith('click', commentBox.onPost); - expect(commentBox.textAreaEl.addEventListener).toBeCalledWith('focus', commentBox.focus); - - commentBox.containerEl = null; - }); - - it('should add an event listener on the textarea, cancel and post buttons if the user is on a touch-enabled mobile device', () => { - commentBox.hasTouch = true; - commentBox.isMobile = true; - - const containerEl = commentBox.createCommentBox(); - expect(containerEl.addEventListener).toBeCalledWith('touchend', expect.any(Function)); - expect(commentBox.postEl.addEventListener).toBeCalledWith('touchend', expect.any(Function)); - expect(commentBox.cancelEl.addEventListener).toBeCalledWith('touchend', expect.any(Function)); - expect(containerEl.addEventListener).toBeCalledWith('click', expect.any(Function)); - - expect(commentBox.cancelEl.addEventListener).not.toBeCalledWith('click', commentBox.onCancel); - expect(commentBox.postEl.addEventListener).not.toBeCalledWith('click', commentBox.onPost); - expect(commentBox.textAreaEl.addEventListener).not.toBeCalledWith('focus', commentBox.focus); - - commentBox.containerEl = null; - }); - }); -}); diff --git a/src/__tests__/CreateAnnotationDialog-test.js b/src/__tests__/CreateAnnotationDialog-test.js deleted file mode 100644 index d629d2fad..000000000 --- a/src/__tests__/CreateAnnotationDialog-test.js +++ /dev/null @@ -1,359 +0,0 @@ -/* eslint-disable no-unused-expressions */ -import CreateAnnotationDialog from '../CreateAnnotationDialog'; -import { - CLASS_MOBILE_CREATE_ANNOTATION_DIALOG, - CLASS_ANNOTATION_DIALOG, - CLASS_HIDDEN, - CREATE_EVENT -} from '../constants'; -import CommentBox from '../CommentBox'; -import * as util from '../util'; - -let dialog; -let parentEl; -const localized = { - highlightToggle: 'highlight toggle', - highlightComment: 'highlight comment' -}; - -describe('CreateAnnotationDialog', () => { - beforeEach(() => { - parentEl = document.createElement('div'); - parentEl.classList.add('ba-create-dialog-container'); - dialog = new CreateAnnotationDialog(parentEl, { - isMobile: true, - localized - }); - - dialog.commentBox = { - containerEl: document.createElement('div'), - hide: jest.fn(), - show: jest.fn(), - focus: jest.fn(), - removeListener: jest.fn(), - destroy: jest.fn(), - clear: jest.fn() - }; - }); - - afterEach(() => { - dialog = null; - parentEl = null; - }); - - describe('contructor()', () => { - it('should take config falsey value to disable highlights and comments, when passed in', () => { - expect(dialog.parentEl).not.toBeUndefined(); - expect(dialog.isMobile).toBeTruthy(); - expect(dialog.hasTouch).toBeFalsy(); - expect(dialog.localized).toEqual(localized); - expect(dialog.isVisible).toBeFalsy(); - }); - }); - - describe('setParentEl()', () => { - it('should assign the new parent reference', () => { - const newParent = document.createElement('span'); - dialog.setParentEl(newParent); - expect(dialog.parentEl).not.toStrictEqual(parentEl); - expect(dialog.parentEl).toStrictEqual(newParent); - }); - }); - - describe('setPosition()', () => { - beforeEach(() => { - dialog.updatePosition = jest.fn(); - }); - - it('should set the x and y coordinates to the passed in values', () => { - const x = 5; - const y = 6; - dialog.setPosition(x, y); - expect(dialog.position.x).toEqual(x); - expect(dialog.position.y).toEqual(y); - }); - - it('should invoke updatePosition()', () => { - dialog.setPosition(0, 0); - expect(dialog.updatePosition).toBeCalled(); - }); - }); - - describe('show()', () => { - it('should invoke createElement() if no UI element has been created', () => { - dialog.createElement = jest.fn(); - dialog.show(); - expect(dialog.createElement).toBeCalled(); - }); - - it('should set the parentEl to a new reference, via setParentEl(), if a new one is supplied', () => { - dialog.setParentEl = jest.fn(); - const newParent = document.createElement('span'); - dialog.show(newParent); - expect(dialog.setParentEl).toBeCalledWith(newParent); - }); - - it('should invoke setButtonVisibility() to show the highlight buttons', () => { - dialog.setButtonVisibility = jest.fn(); - dialog.show(); - expect(dialog.setButtonVisibility).toBeCalled(); - }); - - it('should remove the hidden class from the UI element', () => { - dialog.emit = jest.fn(); - dialog.show(); - expect(dialog.containerEl.classList.contains(CLASS_HIDDEN)).toBeFalsy(); - expect(dialog.emit).toBeCalledWith(CREATE_EVENT.init); - }); - }); - - describe('showCommentBox()', () => { - it('should show and focus comment box', () => { - dialog.commentBox = { - show: jest.fn(), - focus: jest.fn() - }; - dialog.showCommentBox(); - expect(dialog.commentBox.show).toBeCalled(); - expect(dialog.commentBox.focus).toBeCalled(); - }); - }); - - describe('hide()', () => { - beforeEach(() => { - util.hideElement = jest.fn(); - - dialog.containerEl = document.createElement('div'); - dialog.commentBox = { - hide: jest.fn(), - clear: jest.fn() - }; - dialog.isVisible = true; - }); - - afterEach(() => { - expect(dialog.isVisible).toBeFalsy(); - }); - - it('should do nothing if there is no UI element', () => { - dialog.containerEl = null; - dialog.hide(); - expect(dialog.commentBox.hide).not.toBeCalled(); - }); - - it('should add the hidden class to the ui element', () => { - dialog.commentBox = null; - dialog.hide(); - expect(util.hideElement).toBeCalledWith(dialog.containerEl); - }); - - it('should hide and clear the comment box', () => { - dialog.commentBox = { - hide: jest.fn(), - clear: jest.fn() - }; - dialog.hide(); - expect(dialog.commentBox.hide).toBeCalled(); - expect(dialog.commentBox.clear).toBeCalled(); - }); - }); - - describe('destroy()', () => { - let commentBox; - let containerEl; - - beforeEach(() => { - dialog.hide = jest.fn(); - - containerEl = document.createElement('div'); - containerEl.removeEventListener = jest.fn(); - dialog.containerEl = containerEl; - - commentBox = { - removeListener: jest.fn(), - destroy: jest.fn() - }; - dialog.commentBox = commentBox; - }); - - it('should do nothing if no ui has been created', () => { - dialog.containerEl = null; - dialog.destroy(); - expect(dialog.hide).not.toBeCalled(); - }); - - it('should remove events that are bound to stopPropagation()', () => { - dialog.isMobile = false; - dialog.destroy(); - expect(containerEl.removeEventListener).toBeCalledWith('click', expect.any(Function)); - expect(containerEl.removeEventListener).toBeCalledWith('mouseup', expect.any(Function)); - expect(containerEl.removeEventListener).toBeCalledWith('dblclick', expect.any(Function)); - }); - - it('should remove event listeners from the comment box', () => { - dialog.destroy(); - expect(commentBox.removeListener).toBeCalledWith(CommentBox.CommentEvents.post, expect.any(Function)); - expect(commentBox.removeListener).toBeCalledWith(CommentBox.CommentEvents.cancel, expect.any(Function)); - }); - - it('should remove the ui element from the dom', () => { - dialog.destroy(); - expect(commentBox.removeListener).toBeCalled(); - }); - - it('should destroy the comment box', () => { - dialog.destroy(); - expect(commentBox.destroy).toBeCalled(); - }); - - it('should remove out all touch events, if touch enabled', () => { - dialog.hasTouch = true; - dialog.isMobile = true; - - const eventStub = [ - { - stub: containerEl.removeEventListener, - args: ['touchend', dialog.stopPropagation] - } - ]; - - dialog.destroy(); - - eventStub.forEach((stub) => { - expect(stub.stub).toBeCalledWith(...stub.args); - }); - }); - }); - - describe('updatePosition()', () => { - beforeEach(() => { - dialog.isMobile = false; - dialog.containerEl = document.createElement('div'); - dialog.destroy = jest.fn(); - }); - - it('should update the top of the ui element', () => { - const y = 50; - dialog.position.y = y; - dialog.updatePosition(); - expect(dialog.containerEl.style.top).toEqual(`${y + 5}px`); - }); - - it('should update the left of the ui element, to center it', () => { - const width = dialog.containerEl.clientWidth; - const x = 50; - dialog.position.x = x; - dialog.updatePosition(); - expect(dialog.containerEl.style.left).toEqual(`${x - 1 - width / 2}px`); - }); - - it('should do nothing if user is on a mobile device', () => { - const y = 50; - dialog.position.y = y; - dialog.isMobile = true; - dialog.updatePosition(); - expect(dialog.containerEl.style.top).not.toEqual(`${y + 5}px`); - }); - }); - - describe('onCommentPost()', () => { - beforeEach(() => { - dialog.emit = jest.fn(); - dialog.updatePosition = jest.fn(); - dialog.commentBox = { - blur: jest.fn(), - clear: jest.fn() - }; - }); - - it('should invoke the "post" event with the string provided', () => { - const text = 'some text'; - dialog.onCommentPost(text); - expect(dialog.emit).toBeCalledWith(CREATE_EVENT.post, text); - }); - - it('should invoke clear() on the comment box', () => { - dialog.onCommentPost('A message'); - expect(dialog.commentBox.clear).toBeCalled(); - }); - - it('should invoke blur() on the comment box', () => { - dialog.onCommentPost('A message'); - expect(dialog.commentBox.blur).toBeCalled(); - }); - }); - - describe('onCommentCancel()', () => { - beforeEach(() => { - dialog.emit = jest.fn(); - dialog.setButtonVisibility = jest.fn(); - dialog.updatePosition = jest.fn(); - dialog.commentBox = { - hide: jest.fn(), - clear: jest.fn() - }; - }); - - it('should hide the comment box', () => { - dialog.onCommentCancel(); - expect(dialog.commentBox.hide).toBeCalled(); - }); - - it('should show the highlight buttons', () => { - dialog.onCommentCancel(); - expect(dialog.setButtonVisibility).toBeCalledWith(true); - }); - - it('should update the position of the dialog', () => { - dialog.onCommentCancel(); - expect(dialog.updatePosition).toBeCalled(); - }); - }); - - describe('setButtonVisibility()', () => { - it('should show the buttons if given "true"', () => { - util.showElement = jest.fn(); - dialog.setButtonVisibility(true); - expect(util.showElement).toBeCalledWith(dialog.buttonsEl); - }); - - it('should hide the buttons if given "false"', () => { - util.hideElement = jest.fn(); - dialog.setButtonVisibility(false); - expect(util.hideElement).toBeCalledWith(dialog.buttonsEl); - }); - }); - - describe('stopPropagation()', () => { - it('should invoke stopPropagation() on the provided event', () => { - const event = { - stopPropagation: jest.fn() - }; - dialog.stopPropagation(event); - expect(event.stopPropagation).toBeCalled(); - }); - }); - - describe('setupCommentBox', () => { - it('should create a comment box', () => { - dialog.commentBox = undefined; - const box = dialog.setupCommentBox(document.createElement('div')); - expect(box).not.toBeUndefined(); - }); - }); - - describe('createElement()', () => { - it('should create a div with the proper create highlight class', () => { - dialog.createElement(); - expect(dialog.containerEl.nodeName).toEqual('DIV'); - expect(dialog.containerEl.classList.contains(CLASS_MOBILE_CREATE_ANNOTATION_DIALOG)).toBeTruthy(); - expect(dialog.containerEl.classList.contains(CLASS_ANNOTATION_DIALOG)).toBeTruthy(); - }); - - it('should create a comment box', () => { - dialog.setupCommentBox = jest.fn().mockReturnValue(dialog.commentBox); - dialog.createElement(); - expect(dialog.setupCommentBox).toBeCalledWith(dialog.containerEl); - }); - }); -}); diff --git a/src/__tests__/util-test.js b/src/__tests__/util-test.js index 2cfa5a6ff..23f1e971d 100644 --- a/src/__tests__/util-test.js +++ b/src/__tests__/util-test.js @@ -1,63 +1,12 @@ /* eslint-disable no-unused-expressions */ +import * as util from '../util'; import { - findClosestElWithClass, - findClosestDataType, - getPageInfo, - showElement, - hideElement, - enableElement, - disableElement, - showInvisibleElement, - hideElementVisibility, - resetTextarea, - isElementInViewport, - getAvatarHtml, - getScale, - getFirstAnnotation, - getLastAnnotation, - isPlainHighlight, - isHighlightAnnotation, - getDimensionScale, - htmlEscape, - repositionCaret, - isPending, - isPointLocationValid, - isHighlightLocationValid, - isDrawLocationValid, - areThreadParamsValid, - eventToLocationHandler, - decodeKeydown, - getHeaders, - replacePlaceholders, - createLocation, - round, - prevDefAndStopProp, - canLoadAnnotations, - insertTemplate, - generateBtn, - createCommentTextNode, - clearCanvas, - replaceHeader, - isInDialog, - isInAnnotationOrMarker, - focusTextArea, - hasValidBoundaryCoordinates, - generateMobileDialogEl, - getDialogWidth -} from '../util'; -import { - STATES, TYPES, - CLASS_ANNOTATION_COMMENT_TEXT, SELECTOR_ANNOTATION_DIALOG, - SELECTOR_ANNOTATION_CARET, - CLASS_ACTIVE, - SELECTOR_MOBILE_DIALOG_HEADER, - SELECTOR_DIALOG_CLOSE, - SELECTOR_ANNOTATION_PLAIN_HIGHLIGHT, - SELECTOR_ANIMATE_DIALOG, - CLASS_HIDDEN, - SELECTOR_ANNOTATION_POINT_MARKER + CLASS_ANNOTATION_CARET, + SELECTOR_ANNOTATION_POINT_MARKER, + CLASS_ANNOTATION_DIALOG, + CLASS_ANNOTATION_POINT_MARKER } from '../constants'; const DIALOG_WIDTH = 81; @@ -73,11 +22,11 @@ const html = `
-
-
+
+
-
+
`; @@ -102,25 +51,25 @@ describe('util', () => { describe('findClosestElWithClass()', () => { it('should return closest ancestor element with the specified class', () => { - expect(findClosestElWithClass(childEl, 'parent')).toEqual(parentEl); + expect(util.findClosestElWithClass(childEl, 'parent')).toEqual(parentEl); }); it('should return null if no matching ancestor is found', () => { - expect(findClosestElWithClass(childEl, 'otherParent')).toBeNull(); + expect(util.findClosestElWithClass(childEl, 'otherParent')).toBeNull(); }); }); describe('findClosestDataType()', () => { it('should return the data type of the closest ancestor with a data type when no attributeName is provided', () => { - expect(findClosestDataType(childEl)).toEqual('someType'); + expect(util.findClosestDataType(childEl)).toEqual('someType'); }); it('should return the attribute name of the closest ancestor with the specified attributeName', () => { - expect(findClosestDataType(childEl, 'data-name')).toEqual('someName'); + expect(util.findClosestDataType(childEl, 'data-name')).toEqual('someName'); }); it('should return empty string if no matching ancestor is found', () => { - expect(findClosestDataType(childEl, 'data-foo')).toEqual(''); + expect(util.findClosestDataType(childEl, 'data-foo')).toEqual(''); }); }); @@ -128,14 +77,14 @@ describe('util', () => { it('should return page element and page number that the specified element is on', () => { const fooEl = rootElement.querySelector('.foo'); const pageEl = rootElement.querySelector('.page'); - const result = getPageInfo(fooEl); + const result = util.getPageInfo(fooEl); expect(result.pageEl).toEqual(pageEl); expect(result.page).toEqual(2); }); it('should return no page element and -1 page number if no page is found', () => { const barEl = rootElement.querySelector('.bar'); - const result = getPageInfo(barEl); + const result = util.getPageInfo(barEl); expect(result.pageEl).toBeNull(); expect(result.page).toEqual(1); }); @@ -145,26 +94,26 @@ describe('util', () => { it('should remove hidden class from element with matching selector', () => { // Hide element before testing show function childEl.classList.add('bp-is-hidden'); - showElement('.child'); + util.showElement('.child'); expect(childEl.classList).not.toContain('bp-is-hidden'); }); it('should remove hidden class from provided element', () => { // Hide element before testing show function childEl.classList.add('bp-is-hidden'); - showElement(childEl); + util.showElement(childEl); expect(childEl.classList).not.toContain('bp-is-hidden'); }); }); describe('hideElement()', () => { it('should add hidden class to matching element', () => { - hideElement('.child'); + util.hideElement('.child'); expect(childEl.classList).toContain('bp-is-hidden'); }); it('should add hidden class to provided element', () => { - hideElement(childEl); + util.hideElement(childEl); expect(childEl.classList).toContain('bp-is-hidden'); }); }); @@ -173,86 +122,46 @@ describe('util', () => { it('should remove disabled class from matching element', () => { // Hide element before testing show function childEl.classList.add('is-disabled'); - enableElement('.child'); + util.enableElement('.child'); expect(childEl.classList).not.toContain('is-disabled'); }); it('should remove disabled class from provided element', () => { // Hide element before testing show function childEl.classList.add('is-disabled'); - enableElement(childEl); + util.enableElement(childEl); expect(childEl.classList).not.toContain('is-disabled'); }); }); describe('disableElement()', () => { it('should add disabled class to matching element', () => { - disableElement('.child'); + util.disableElement('.child'); expect(childEl.classList).toContain('is-disabled'); }); it('should add disabled class to provided element', () => { - disableElement(childEl); + util.disableElement(childEl); expect(childEl.classList).toContain('is-disabled'); }); }); - describe('showInvisibleElement()', () => { - it('should remove invisible class from element with matching selector', () => { - // Hide element before testing show function - childEl.classList.add('bp-is-invisible'); - showInvisibleElement('.child'); - expect(childEl.classList).not.toContain('bp-is-invisible'); - }); - - it('should remove invisible class from provided element', () => { - // Hide element before testing show function - childEl.classList.add('bp-is-invisible'); - showInvisibleElement(childEl); - expect(childEl.classList).not.toContain('bp-is-invisible'); - }); - }); - - describe('hideElementVisibility()', () => { - it('should add invisible class to matching element', () => { - hideElementVisibility('.child'); - expect(childEl.classList).toContain('bp-is-invisible'); - }); - - it('should add invisible class to provided element', () => { - hideElementVisibility(childEl); - expect(childEl.classList).toContain('bp-is-invisible'); - }); - }); - - describe('resetTextarea()', () => { - it('should reset text area', () => { - const textAreaEl = rootElement.querySelector('.textarea'); - - // Fake making text area 'active' - textAreaEl.classList.add(CLASS_ACTIVE); - textAreaEl.value = 'test'; - textAreaEl.style.width = '10px'; - textAreaEl.style.height = '10px'; - - resetTextarea(textAreaEl); - - expect(textAreaEl.classList).not.toContain(CLASS_ACTIVE); - expect(textAreaEl.classList).not.toContain('ba-invalid-input'); - expect(textAreaEl.value).toEqual('test'); - expect(textAreaEl.style.width).toEqual(''); - expect(textAreaEl.style.height).toEqual(''); - }); - }); - describe('isInDialog()', () => { it('should return false if no dialog element exists', () => { - expect(isInDialog({ clientX: 8, clientY: 8 })).toBeFalsy(); + expect(util.isInDialog({ clientX: 8, clientY: 8 })).toBeFalsy(); }); it('should return true if the event is in the given dialog', () => { - const dialogEl = rootElement.querySelector(SELECTOR_ANNOTATION_DIALOG); - expect(isInDialog({ clientX: 8, clientY: 8 }, dialogEl)).toBeTruthy(); + const actionControls = document.createElement('div'); + actionControls.classList.add('ba-action-controls'); + rootElement.appendChild(actionControls); + actionControls.getBoundingClientRect = jest.fn().mockReturnValue({ + left: 0, + right: 10, + top: 0, + bottom: 10 + }); + expect(util.isInDialog({ clientX: 8, clientY: 8 }, rootElement)).toBeTruthy(); }); }); @@ -260,9 +169,9 @@ describe('util', () => { it('should return false if no dialog element exists', () => { const dialogEl = rootElement.querySelector(SELECTOR_ANNOTATION_DIALOG); const markerEl = rootElement.querySelector(SELECTOR_ANNOTATION_POINT_MARKER); - expect(isInAnnotationOrMarker({ target: dialogEl })).toBeTruthy(); - expect(isInAnnotationOrMarker({ target: markerEl })).toBeTruthy(); - expect(isInAnnotationOrMarker({ target: document.createElement('div') })).toBeFalsy(); + expect(util.isInAnnotationOrMarker({ target: dialogEl })).toBeTruthy(); + expect(util.isInAnnotationOrMarker({ target: markerEl })).toBeTruthy(); + expect(util.isInAnnotationOrMarker({ target: document.createElement('div') })).toBeFalsy(); }); }); @@ -276,103 +185,53 @@ describe('util', () => { createContextualFragment: jest.fn() }); - insertTemplate(node, '
'); + util.insertTemplate(node, '
'); expect(node.insertBefore).toBeCalled(); }); }); - describe('generateBtn()', () => { - it('should return button node from specified details', () => { - const btn = generateBtn(['class', 'bp-btn-plain'], 'title', document.createElement('div'), 'type'); - expect(btn.classList).not.toContain('nope'); - expect(btn.classList).toContain('bp-btn-plain'); - expect(btn.classList).toContain('class'); - expect(btn.dataset.type).toEqual('type'); - expect(btn.title).toEqual('title'); - expect(btn.innerHTML).toContain(document.createElement('div')); - }); - }); - - describe('isElementInViewport()', () => { - it('should return true for an element fully in the viewport', () => { - expect(isElementInViewport(childEl)).toBeTruthy(); - }); - }); - - describe('getAvatarHtml()', () => { - it('should return avatar HTML with img if avatarUrl is provided', () => { - const expectedHtml = 'Avatar'; - expect(getAvatarHtml('https://example.com', '1', 'Some Name', 'Avatar')).toEqual(expectedHtml); - }); - - it('should return avatar HTML initials if no avatarUrl is provided', () => { - const expectedHtml = '
SN
'.trim(); - expect(getAvatarHtml('', '1', 'Some Name')).toEqual(expectedHtml); - }); - }); - describe('getScale()', () => { it('should return the zoom scale stored in the data-zoom attribute for the element', () => { childEl.setAttribute('data-scale', 3); - expect(getScale(childEl)).toEqual(3); + expect(util.getScale(childEl)).toEqual(3); }); it('should return a zoom scale of 1 if no stored zoom is found on the element', () => { - expect(getScale(childEl)).toEqual(1); - }); - }); - - describe('getFirstAnnotation()', () => { - it('should return the first annotation in thread', () => { - const annotations = { - def123: { id: 1 }, - abc456: { id: 2 } - }; - expect(getFirstAnnotation(annotations)).toStrictEqual({ id: 1 }); - }); - }); - - describe('getLastAnnotation()', () => { - it('should return the last annotation in thread', () => { - const annotations = { - def123: { id: 1 }, - abc456: { id: 2 } - }; - expect(getLastAnnotation(annotations)).toStrictEqual({ id: 2 }); + expect(util.getScale(childEl)).toEqual(1); }); }); describe('isPlainHighlight()', () => { it('should return true if highlight annotation is a plain highlight', () => { - const annotations = [{ text: '' }]; + const annotations = [{ message: '' }]; - expect(isPlainHighlight(annotations)).toBeTruthy(); + expect(util.isPlainHighlight(annotations)).toBeTruthy(); }); it('should return false if a plain highlight annotation had comments added to it', () => { - const annotations = [{ text: '' }, { text: 'bleh' }]; + const annotations = [{ message: '' }, { message: 'bleh' }]; - expect(isPlainHighlight(annotations)).toBeFalsy(); + expect(util.isPlainHighlight(annotations)).toBeFalsy(); }); it('should return false if highlight annotation has comments', () => { - const annotations = [{ text: 'bleh' }]; + const annotations = [{ message: 'bleh' }]; - expect(isPlainHighlight(annotations)).toBeFalsy(); + expect(util.isPlainHighlight(annotations)).toBeFalsy(); }); }); describe('isHighlightAnnotation()', () => { it('should return true if annotation is a plain highlight annotation', () => { - expect(isHighlightAnnotation(TYPES.highlight)).toBeTruthy(); + expect(util.isHighlightAnnotation(TYPES.highlight)).toBeTruthy(); }); it('should return true if annotation is a highlight comment annotation', () => { - expect(isHighlightAnnotation(TYPES.highlight_comment)).toBeTruthy(); + expect(util.isHighlightAnnotation(TYPES.highlight_comment)).toBeTruthy(); }); it('should return false if annotation is a point annotation', () => { - expect(isHighlightAnnotation(TYPES.point)).toBeFalsy(); + expect(util.isHighlightAnnotation(TYPES.point)).toBeFalsy(); }); }); @@ -388,7 +247,7 @@ describe('util', () => { }; const HEIGHT_PADDING = 30; - const result = getDimensionScale(dimensions, pageDimensions, 1, HEIGHT_PADDING); + const result = util.getDimensionScale(dimensions, pageDimensions, 1, HEIGHT_PADDING); expect(result).toBeNull(); }); @@ -403,133 +262,49 @@ describe('util', () => { }; const HEIGHT_PADDING = 30; - const result = getDimensionScale(dimensions, pageDimensions, 1, HEIGHT_PADDING); + const result = util.getDimensionScale(dimensions, pageDimensions, 1, HEIGHT_PADDING); expect(result.x).toEqual(2); expect(result.y).toEqual(2); }); }); - describe('htmlEscape()', () => { - it('should return HTML-escaped text', () => { - expect(htmlEscape('test&file=what')).toEqual('test&file=what'); - expect(htmlEscape('