diff --git a/.circleci/config.yml b/.circleci/config.yml index a13704284..f10a9a705 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,7 +3,7 @@ version: 2 jobs: "server-test": docker: - - image: circleci/python:3.6.7-node-browsers + - image: circleci/python:3.6-node-browsers - image: cypress/base:10 steps: @@ -12,7 +12,7 @@ jobs: key: deps1-{{ .Branch }}-{{ checksum "package-lock.json" }}-{{ checksum "package.json" }}-{{ checksum ".circleci/config.yml" }} - run: name: Install npm packages - command: npm install + command: npm ci - run: name: Cypress Install command: | @@ -60,7 +60,7 @@ jobs: key: deps1-{{ .Branch }}-{{ checksum "package-lock.json" }}-{{ checksum "package.json" }}-{{ checksum ".circleci/config.yml" }} - run: name: Install npm packages - command: npm install + command: npm ci - run: name: Cypress Install command: | @@ -74,12 +74,15 @@ jobs: - run: name: Run tests - command: npm run test.standalone + command: | + rm -rf node_modules/cypress + npm i cypress@3.4.1 + npm run test.standalone "unit-test": docker: - - image: circleci/python:3.6.7-node-browsers + - image: circleci/python:3.6-node-browsers - image: cypress/base:10 steps: @@ -88,7 +91,7 @@ jobs: key: deps1-{{ .Branch }}-{{ checksum "package-lock.json" }}-{{ checksum "package.json" }}-{{ checksum ".circleci/config.yml" }} - run: name: Install npm packages - command: npm install + command: npm ci - run: name: Cypress Install command: | @@ -148,7 +151,7 @@ jobs: "node": docker: - - image: circleci/python:3.6.7-node + - image: circleci/python:3.6-node steps: - checkout @@ -185,7 +188,7 @@ jobs: "python-3.6": docker: - - image: circleci/python:3.6.7-stretch-node-browsers + - image: circleci/python:3.6-stretch-node-browsers environment: PERCY_ENABLED: True @@ -206,7 +209,7 @@ jobs: python -m venv venv || virtualenv venv . venv/bin/activate pip install -r dev-requirements.txt --quiet - npm install + npm ci - run: name: Install dependencies (dash) diff --git a/.config/webpack/base.js b/.config/webpack/base.js index ba471c134..b15636ed7 100644 --- a/.config/webpack/base.js +++ b/.config/webpack/base.js @@ -9,20 +9,18 @@ const dashLibraryName = packagejson.name.replace(/-/g, '_'); module.exports = (options = {}) => { const babel = options.babel || undefined; + const entry = options.entry || []; const preprocessor = basePreprocessing(options.preprocessor); const mode = options.mode || 'development'; const ts = options.ts || {}; console.log('********** Webpack Environment Overrides **********'); - console.log('Preprocessor', JSON.stringify(preprocessor)); - console.log('mode', mode); - console.log('babel', JSON.stringify(babel)); - console.log('ts', JSON.stringify(ts)); + console.log('options', JSON.stringify(options)); return { entry: { - bundle: './src/dash-table/index.ts', - demo: ['./demo/index.html', './demo/index.js'] + bundle: entry.concat(['./src/dash-table/index.ts']), + demo: entry.concat(['./demo/index.html', './demo/index.js']) }, mode: mode, output: { diff --git a/.storybook/babel.config.js b/.storybook/babel.config.js index fd1727561..1befb89e6 100644 --- a/.storybook/babel.config.js +++ b/.storybook/babel.config.js @@ -6,4 +6,8 @@ const presets = [ '@babel/preset-react' ]; -module.exports = { presets }; +const plugins = [ + '@babel/plugin-transform-regenerator' +]; + +module.exports = { presets, plugins }; diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d527f173..c0b1ca499 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [Unreleased] +### Fixes +- [#637](https://github.com/plotly/dash-table/pull/637) Fix multiple issues + - Fix IE11 compatibility issues and add ES5 compatibility and validation + - Fix a bug with `loading_state` being handled incorrectly, causing the table to steal focus + ## [4.5.0] - 2019-10-29 ### Changed - [#554](https://github.com/plotly/dash-table/pull/554) Async loading of `xlsx` library on export diff --git a/babel.config.js b/babel.config.js index f33e85832..dcf4bdf55 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,17 +1,5 @@ const presets = [ - ['@babel/env', { - targets: { - browsers: [ - 'last 2 Chrome versions', - 'last 2 Firefox versions', - 'last 2 Safari versions', - 'last 2 Edge versions', - 'Explorer 11' - ] - }, - useBuiltIns: 'usage', - corejs: 3 - }], + '@babel/preset-env', '@babel/preset-react' ]; @@ -19,4 +7,4 @@ const plugins = [ '@babel/plugin-syntax-dynamic-import' ]; -module.exports = { presets }; +module.exports = { presets, plugins }; diff --git a/demo/App.tsx b/demo/App.tsx index 6a7ce3121..843638280 100644 --- a/demo/App.tsx +++ b/demo/App.tsx @@ -1,6 +1,7 @@ /* eslint no-magic-numbers: 0 */ +import '@babel/polyfill/noConflict'; import * as R from 'ramda'; -import React, {Component} from 'react'; +import React, { Component } from 'react'; import { DataTable } from 'dash-table/index'; import Environment from 'core/environment'; import { memoizeOne } from 'core/memoizer'; diff --git a/package-lock.json b/package-lock.json index 6ef1b0cb8..bfb777da7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1256,9 +1256,9 @@ } }, "@babel/plugin-transform-regenerator": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.4.5.tgz", - "integrity": "sha512-gBKRh5qAaCWntnd09S8QC7r3auLCqq5DI6O0DlfoyDjslSBVqBibrMdsqO+Uhmx3+BlOmE/Kw1HFxmGbv0N9dA==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.7.0.tgz", + "integrity": "sha512-AXmvnC+0wuj/cFkkS/HFHIojxH3ffSXE+ttulrqWjZZRaUOonfJc60e1wSNT4rV8tIunvu/R3wCp71/tLAa9xg==", "dev": true, "requires": { "regenerator-transform": "^0.14.0" @@ -1363,9 +1363,9 @@ } }, "@babel/polyfill": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.6.0.tgz", - "integrity": "sha512-q5BZJI0n/B10VaQQvln1IlDK3BTBJFbADx7tv+oXDPIDZuTo37H5Adb9jhlXm/fEN4Y7/64qD9mnrJJG7rmaTw==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.7.0.tgz", + "integrity": "sha512-/TS23MVvo34dFmf8mwCisCbWGrfhbiWZSwBo6HkADTBhUa2Q/jWltyY/tpofz/b6/RIhqaqQcquptCirqIhOaQ==", "dev": true, "requires": { "core-js": "^2.6.5", @@ -1373,9 +1373,9 @@ }, "dependencies": { "core-js": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.9.tgz", - "integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==", + "version": "2.6.10", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.10.tgz", + "integrity": "sha512-I39t74+4t+zau64EN1fE5v2W31Adtc/REhzWN+gWRRXg6WH5qAsZm62DHpQ1+Yhe4047T55jvzz7MUqF/dBBlA==", "dev": true }, "regenerator-runtime": { @@ -2247,15 +2247,15 @@ } }, "@plotly/dash-component-plugins": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@plotly/dash-component-plugins/-/dash-component-plugins-1.0.1.tgz", - "integrity": "sha512-z3KTahhLhIw3RZL49OOutyV8ePn2kZLCnMBoWYPy5sr55Yd2ghL7aDDyO1yseintG+RTm72n6UB35G++mvNbpA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@plotly/dash-component-plugins/-/dash-component-plugins-1.0.2.tgz", + "integrity": "sha512-KBO+rZk0MAht3/cqdzKd5GUc6EJDWj7OTPw9u6Q4HALbaO9KzvYFXN0PdiNGPv4y1bINjPBI3bw6i4smqVrrEw==", "dev": true }, "@plotly/webpack-dash-dynamic-import": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@plotly/webpack-dash-dynamic-import/-/webpack-dash-dynamic-import-1.1.1.tgz", - "integrity": "sha512-Yrc7XZOMQuyh2TkbEMr3i6hfdAS/DMFDfvhdD3C28/G6aRWfPRTZ2Tb+IeyOhZTX41IoNmJ6YciLooME8zP5ag==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@plotly/webpack-dash-dynamic-import/-/webpack-dash-dynamic-import-1.1.4.tgz", + "integrity": "sha512-inRFhwD48F8zDHKUGB8cVWlUTtZ3kDLuYMXE9XEmVhPlGUo/oMi9sU6XgPtrfGF1jWuERIDQECjTZ3AE1+rzCw==", "dev": true }, "@reach/router": { @@ -3452,6 +3452,12 @@ } } }, + "@types/sizzle": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.2.tgz", + "integrity": "sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg==", + "dev": true + }, "@webassemblyjs/ast": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz", @@ -3747,6 +3753,12 @@ "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=", "dev": true }, + "ansi": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.1.tgz", + "integrity": "sha1-DELU+xcWDVqa8eSEus4cZpIsGyE=", + "dev": true + }, "ansi-align": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", @@ -5420,6 +5432,25 @@ "integrity": "sha512-gcu45yfq3B7Y+WB05fOMfr0EiSlq+1u+m6rPHyJli/Wy3PVQNGaU7VA4bZE5qw+AU2UVOBR/N5g1bzADUqdvFw==", "dev": true }, + "caporal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/caporal/-/caporal-1.1.0.tgz", + "integrity": "sha512-R5qo2QGoqBM6RvzHonGhUuEJSeqEa4lD1r+cPUEY2+YsXhpQVTS2TvScfIbi6ydFdhzFCNeNUB1v0YrRBvsbdg==", + "dev": true, + "requires": { + "bluebird": "^3.4.7", + "cli-table3": "^0.5.0", + "colorette": "1.0.1", + "fast-levenshtein": "^2.0.6", + "lodash.camelcase": "^4.3.0", + "lodash.kebabcase": "^4.1.1", + "lodash.merge": "^4.6.0", + "micromist": "1.1.0", + "prettyjson": "^1.2.1", + "tabtab": "^2.2.2", + "winston": "^2.3.1" + } + }, "case-sensitive-paths-webpack-plugin": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.2.0.tgz", @@ -5831,6 +5862,12 @@ "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=", "dev": true }, + "colorette": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.0.1.tgz", + "integrity": "sha512-40MnlppkzHhFjRhtXunbpqKUT+eJn0gyVGi8aQlNSG8T2CCy31NdD7yktcS0aizH1VP2OhhQCyGMeTp0a/fvaw==", + "dev": true + }, "colors": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz", @@ -6448,6 +6485,12 @@ "integrity": "sha512-r4DbsyNJ7slwBSKoGesxDubRWJ71ghG8W2+1HcsDlAo12KGca9dDLv0u98tfdFw7ldBdoA7XmCnI6Q8LpAJXaQ==", "dev": true }, + "cycle": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", + "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=", + "dev": true + }, "cyclist": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", @@ -6455,13 +6498,14 @@ "dev": true }, "cypress": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-3.4.1.tgz", - "integrity": "sha512-1HBS7t9XXzkt6QHbwfirWYty8vzxNMawGj1yI+Fu6C3/VZJ8UtUngMW6layqwYZzLTZV8tiDpdCNBypn78V4Dg==", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-3.6.1.tgz", + "integrity": "sha512-6n0oqENdz/oQ7EJ6IgESNb2M7Bo/70qX9jSJsAziJTC3kICfEMmJUlrAnP9bn+ut24MlXQST5nRXhUP5nRIx6A==", "dev": true, "requires": { "@cypress/listr-verbose-renderer": "0.4.1", "@cypress/xvfb": "1.2.4", + "@types/sizzle": "2.3.2", "arch": "2.1.1", "bluebird": "3.5.0", "cachedir": "1.3.0", @@ -6488,6 +6532,7 @@ "request-progress": "3.0.0", "supports-color": "5.5.0", "tmp": "0.1.0", + "untildify": "3.0.3", "url": "0.11.0", "yauzl": "2.10.0" }, @@ -6607,9 +6652,9 @@ } }, "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -7606,6 +7651,25 @@ "is-regex": "^1.0.4" } }, + "es-check": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es-check/-/es-check-5.0.0.tgz", + "integrity": "sha512-30n+EZt5KjazXEvyYr2DXJCOJJWfdT1unRp5+Szlcja6uGAB3Sh3QPjRsxd2xgN9SFj4S5P8pdBISwGcDdS45Q==", + "dev": true, + "requires": { + "acorn": "6.0.4", + "caporal": "1.1.0", + "glob": "^7.1.2" + }, + "dependencies": { + "acorn": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.4.tgz", + "integrity": "sha512-VY4i5EKSKkofY2I+6QLTbTTN/UvEQPCo6eiwzzSaSWfpaDhOmStMCMod6wmuPciNq+XS0faCglFu2lHZpdHUtg==", + "dev": true + } + } + }, "es-to-primitive": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz", @@ -7997,6 +8061,12 @@ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", "dev": true }, + "eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=", + "dev": true + }, "fast-deep-equal": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", @@ -8032,6 +8102,12 @@ "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", "dev": true }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, "fault": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.3.tgz", @@ -11236,30 +11312,78 @@ "integrity": "sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ==", "dev": true }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=", + "dev": true + }, "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", "dev": true }, + "lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=", + "dev": true + }, + "lodash.kebabcase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", + "integrity": "sha1-hImxyw0p/4gZXM7KRI/21swpXDY=", + "dev": true + }, "lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", "dev": true }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, "lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=", "dev": true }, + "lodash.pad": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/lodash.pad/-/lodash.pad-4.5.1.tgz", + "integrity": "sha1-QzCUmoM6fI2iLMIPaibE1Z3runA=", + "dev": true + }, + "lodash.padend": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.padend/-/lodash.padend-4.6.1.tgz", + "integrity": "sha1-U8y6BH0G4VjTEfRdpiX05J5vFm4=", + "dev": true + }, + "lodash.padstart": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.padstart/-/lodash.padstart-4.6.1.tgz", + "integrity": "sha1-0uPuv/DZ05rVD1y9G1KnvOa7YRs=", + "dev": true + }, "lodash.throttle": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=", "dev": true }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", + "dev": true + }, "log-symbols": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", @@ -11548,6 +11672,15 @@ "to-regex": "^3.0.2" } }, + "micromist": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromist/-/micromist-1.1.0.tgz", + "integrity": "sha512-+CQ76pabE9egniSEdmDuH+j2cYyIBKP97kujG8ZLZyLCRq5ExwtIy4DPHPFrq4jVbhMRBnyjuH50KU9Ohs8QCg==", + "dev": true, + "requires": { + "lodash.camelcase": "^4.3.0" + } + }, "miller-rabin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", @@ -15890,6 +16023,12 @@ } } }, + "os-shim": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz", + "integrity": "sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc=", + "dev": true + }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", @@ -16546,6 +16685,24 @@ "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", "dev": true }, + "prettyjson": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prettyjson/-/prettyjson-1.2.1.tgz", + "integrity": "sha1-/P+rQdGcq0365eV15kJGYZsS0ok=", + "dev": true, + "requires": { + "colors": "^1.1.2", + "minimist": "^1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, "printj": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz", @@ -18749,6 +18906,16 @@ "integrity": "sha512-UyhMSmeIqZrQn2UdjYpxEkwY9JUrn8pP+7L4f91zRzOQuI8MF1FGLfYU9DKCYeLdo7LXMxwrX5zKFy7eeeVHuA==", "dev": true }, + "spawn-sync": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz", + "integrity": "sha1-sAeZVX63+wyDdsKdROih6mfldHY=", + "dev": true, + "requires": { + "concat-stream": "^1.4.7", + "os-shim": "^0.1.2" + } + }, "spdx-correct": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", @@ -18909,6 +19076,12 @@ "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", "dev": true }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "dev": true + }, "staged-git-files": { "version": "1.1.1", "resolved": "http://registry.npmjs.org/staged-git-files/-/staged-git-files-1.1.1.tgz", @@ -19287,6 +19460,188 @@ "has-symbols": "^1.0.0" } }, + "tabtab": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tabtab/-/tabtab-2.2.2.tgz", + "integrity": "sha1-egR/FDsBC0y9MfhX6ClhUSy/ThQ=", + "dev": true, + "requires": { + "debug": "^2.2.0", + "inquirer": "^1.0.2", + "lodash.difference": "^4.5.0", + "lodash.uniq": "^4.5.0", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "npmlog": "^2.0.3", + "object-assign": "^4.1.0" + }, + "dependencies": { + "ansi-escapes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", + "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "cli-cursor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", + "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", + "dev": true, + "requires": { + "restore-cursor": "^1.0.1" + } + }, + "external-editor": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-1.1.1.tgz", + "integrity": "sha1-Etew24UPf/fnCBuvQAVwAGDEYAs=", + "dev": true, + "requires": { + "extend": "^3.0.0", + "spawn-sync": "^1.0.15", + "tmp": "^0.0.29" + } + }, + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" + } + }, + "gauge": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-1.2.7.tgz", + "integrity": "sha1-6c7FSD09TuDvRLYKfZnkk14TbZM=", + "dev": true, + "requires": { + "ansi": "^0.3.0", + "has-unicode": "^2.0.0", + "lodash.pad": "^4.1.0", + "lodash.padend": "^4.1.0", + "lodash.padstart": "^4.1.0" + } + }, + "inquirer": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-1.2.3.tgz", + "integrity": "sha1-TexvMvN+97sLLtPx0aXD9UUHSRg=", + "dev": true, + "requires": { + "ansi-escapes": "^1.1.0", + "chalk": "^1.0.0", + "cli-cursor": "^1.0.1", + "cli-width": "^2.0.0", + "external-editor": "^1.1.0", + "figures": "^1.3.5", + "lodash": "^4.3.0", + "mute-stream": "0.0.6", + "pinkie-promise": "^2.0.0", + "run-async": "^2.2.0", + "rx": "^4.1.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.0", + "through": "^2.3.6" + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "mute-stream": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.6.tgz", + "integrity": "sha1-SJYrGeFp/R38JAs/HnMXYnu8R9s=", + "dev": true + }, + "npmlog": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-2.0.4.tgz", + "integrity": "sha1-mLUlMPJRTKkNCexbIsiEZyI3VpI=", + "dev": true, + "requires": { + "ansi": "~0.3.1", + "are-we-there-yet": "~1.1.2", + "gauge": "~1.2.5" + } + }, + "onetime": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", + "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", + "dev": true + }, + "restore-cursor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", + "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", + "dev": true, + "requires": { + "exit-hook": "^1.0.0", + "onetime": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "tmp": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.29.tgz", + "integrity": "sha1-8lEl/w3Z2jzLDC3Tce4SiLuRKMA=", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.1" + } + } + } + }, "tapable": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", @@ -19948,6 +20303,12 @@ } } }, + "untildify": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-3.0.3.tgz", + "integrity": "sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA==", + "dev": true + }, "upath": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz", @@ -20847,6 +21208,34 @@ "string-width": "^2.1.1" } }, + "winston": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.4.tgz", + "integrity": "sha512-NBo2Pepn4hK4V01UfcWcDlmiVTs7VTB1h7bgnB0rgP146bYhMxX0ypCz3lBOfNxCO4Zuek7yeT+y/zM1OfMw4Q==", + "dev": true, + "requires": { + "async": "~1.0.0", + "colors": "1.0.x", + "cycle": "1.0.x", + "eyes": "0.1.x", + "isstream": "0.1.x", + "stack-trace": "0.0.x" + }, + "dependencies": { + "async": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz", + "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=", + "dev": true + }, + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", + "dev": true + } + } + }, "worker-farm": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", diff --git a/package.json b/package.json index 9ff8d6244..7c0d257cd 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "private::test.standalone": "cypress run --browser chrome --spec 'tests/cypress/tests/standalone/**/*'", "build.watch": "webpack-dev-server --content-base dash_table --mode development --config webpack.dev.config.js", "build": "run-s private::build:js private::build:py", + "postbuild": "es-check es5 dash_table/*.js", "format": "run-s \"private::lint:ts -- --fix\"", "lint": "run-s private::lint:*", "test.server": "run-p --race private::host* private::test.server", @@ -62,7 +63,8 @@ "@babel/cli": "^7.6.2", "@babel/core": "^7.6.2", "@babel/plugin-syntax-dynamic-import": "^7.2.0", - "@babel/polyfill": "^7.6.0", + "@babel/plugin-transform-regenerator": "^7.7.0", + "@babel/polyfill": "^7.7.0", "@babel/preset-env": "^7.6.2", "@babel/preset-react": "^7.0.0", "@cypress/webpack-preprocessor": "^4.1.0", @@ -71,8 +73,8 @@ "@fortawesome/free-solid-svg-icons": "^5.11.2", "@fortawesome/react-fontawesome": "^0.1.4", "@percy/storybook": "^3.2.0", - "@plotly/dash-component-plugins": "^1.0.1", - "@plotly/webpack-dash-dynamic-import": "^1.1.1", + "@plotly/dash-component-plugins": "^1.0.2", + "@plotly/webpack-dash-dynamic-import": "^1.1.4", "@storybook/cli": "^5.1.11", "@storybook/react": "^5.1.11", "@types/d3-format": "^1.3.1", @@ -82,10 +84,10 @@ "@types/react-dom": "^16.9.0", "@types/react-select": "^1.3.4", "babel-loader": "^8.0.6", - "core-js": "^3.2.1", "css-loader": "^3.2.0", - "cypress": "^3.4.1", + "cypress": "^3.6.1", "d3-format": "^1.4.1", + "es-check": "^5.0.0", "fast-isnumeric": "^1.1.3", "file-loader": "^4.2.0", "http-server": "^0.11.1", @@ -126,4 +128,4 @@ "node": ">=8.11.0", "npm": ">=6.1.0" } -} \ No newline at end of file +} diff --git a/src/core/browser/DOM.ts b/src/core/browser/DOM.ts index 04be859e4..510ff0f92 100644 --- a/src/core/browser/DOM.ts +++ b/src/core/browser/DOM.ts @@ -1,8 +1,8 @@ export default class DOM { - public static getFirstParentOfType(element: HTMLElement, type: string): HTMLElement | undefined { + public static getFirstParentOfType(element: HTMLElement | undefined, type: string): HTMLElement | undefined { type = type.toUpperCase(); - let current: HTMLElement = element; + let current: HTMLElement | undefined = element; while (current) { if (current.tagName.toUpperCase() === type) { return current; @@ -15,4 +15,19 @@ export default class DOM { } } } + + public static getParentById(element: HTMLElement | undefined, id: string): HTMLElement | undefined { + let current: HTMLElement | undefined = element; + while (current) { + if (current.id === id) { + return current; + } + + if (current.parentElement !== null) { + current = current.parentElement; + } else { + return; + } + } + } } \ No newline at end of file diff --git a/src/dash-table/components/CellDropdown/index.tsx b/src/dash-table/components/CellDropdown/index.tsx index 801d4e521..30ae7a184 100644 --- a/src/dash-table/components/CellDropdown/index.tsx +++ b/src/dash-table/components/CellDropdown/index.tsx @@ -12,6 +12,7 @@ import { IDropdownValue } from '../Table/props'; interface IProps { active: boolean; + applyFocus: boolean; clearable?: boolean; dropdown?: IDropdownValue[]; onChange: (e: ChangeEvent) => void; @@ -64,14 +65,14 @@ export default class CellDropdown extends PureComponent { } private setFocus() { - const { active } = this.props; + const { active, applyFocus } = this.props; if (!active) { return; } const dropdown = this.refs.dropdown as any; - if (dropdown && document.activeElement !== dropdown) { + if (applyFocus && dropdown && document.activeElement !== dropdown) { // Limitation. If React >= 16 --> Use React.createRef instead to pass parent ref to child const tdParent = DOM.getFirstParentOfType(dropdown.wrapper, 'td'); if (tdParent) { diff --git a/src/dash-table/components/CellFactory.tsx b/src/dash-table/components/CellFactory.tsx index bafb906fd..e35fc19e9 100644 --- a/src/dash-table/components/CellFactory.tsx +++ b/src/dash-table/components/CellFactory.tsx @@ -15,8 +15,6 @@ import { IEdgesMatrices } from 'dash-table/derived/edges/type'; import { memoizeOne } from 'core/memoizer'; import memoizerCache from 'core/cache/memoizer'; -import dataLoading from 'dash-table/derived/table/data_loading'; - export default class CellFactory { private get props() { @@ -38,12 +36,14 @@ export default class CellFactory { public createCells(dataEdges: IEdgesMatrices | undefined, dataOpEdges: IEdgesMatrices | undefined) { const { active_cell, + applyFocus, dropdown_conditional, dropdown, data, dropdown_data, id, is_focused, + loading_state, row_deletable, row_selectable, selected_cells, @@ -54,8 +54,7 @@ export default class CellFactory { style_data, style_data_conditional, virtualized, - visibleColumns, - loading_state + visibleColumns } = this.props; const relevantStyles = this.relevantStyles( @@ -118,26 +117,25 @@ export default class CellFactory { selected_cells ); - const data_loading = dataLoading(loading_state); - const partialCellContents = this.cellContents.partialGet( visibleColumns, virtualized.data, virtualized.offset, !!is_focused, dropdowns, - data_loading + loading_state ); const cellContents = this.cellContents.get( partialCellContents, active_cell, + applyFocus || false, visibleColumns, virtualized.data, virtualized.offset, !!is_focused, dropdowns, - data_loading + loading_state ); const ops = this.getDataOpCells( diff --git a/src/dash-table/components/CellInput/index.tsx b/src/dash-table/components/CellInput/index.tsx index 3e3b32344..5c02ab2e8 100644 --- a/src/dash-table/components/CellInput/index.tsx +++ b/src/dash-table/components/CellInput/index.tsx @@ -12,6 +12,7 @@ import { interface ICellProps { active: boolean; + applyFocus: boolean; className: string; focused: boolean; onChange: (e: ChangeEvent) => void; @@ -115,14 +116,14 @@ export default class CellInput extends PureComponent { } private setFocus() { - const { active } = this.props; + const { active, applyFocus } = this.props; if (!active) { return; } const input = this.refs.textInput as HTMLInputElement; - if (input && document.activeElement !== input) { + if (applyFocus && input && document.activeElement !== input) { input.focus(); input.setSelectionRange(0, input.value ? input.value.length : 0); } diff --git a/src/dash-table/components/CellLabel/index.tsx b/src/dash-table/components/CellLabel/index.tsx index 23da68414..03ff5f96b 100644 --- a/src/dash-table/components/CellLabel/index.tsx +++ b/src/dash-table/components/CellLabel/index.tsx @@ -4,6 +4,7 @@ import React, { interface IProps { active: boolean; + applyFocus: boolean; className: string; value: any; } @@ -35,14 +36,14 @@ export default class CellLabel extends PureComponent { } private setFocus() { - const { active } = this.props; + const { active, applyFocus } = this.props; if (!active) { return; } const el = this.refs.el as HTMLDivElement; - if (el && document.activeElement !== el) { + if (applyFocus && el && document.activeElement !== el) { el.focus(); } } diff --git a/src/dash-table/components/ControlledTable/index.tsx b/src/dash-table/components/ControlledTable/index.tsx index da46d47d3..e536cf8e9 100644 --- a/src/dash-table/components/ControlledTable/index.tsx +++ b/src/dash-table/components/ControlledTable/index.tsx @@ -35,7 +35,6 @@ import TableTooltip from './fragments/TableTooltip'; import queryLexicon from 'dash-table/syntax-tree/lexicon/query'; -import dataLoading from 'dash-table/derived/table/data_loading'; import reconcile from 'dash-table/type/reconcile'; import PageNavigation from 'dash-table/components/PageNavigation'; @@ -591,15 +590,15 @@ export default class ControlledTable extends PureComponent data, editable, filter_query, + loading_state, setProps, sort_by, viewport, visibleColumns, - include_headers_on_copy_paste, - loading_state + include_headers_on_copy_paste } = this.props; - if (!editable || !active_cell || dataLoading(loading_state)) { + if (!editable || !active_cell || loading_state) { return; } @@ -738,8 +737,6 @@ export default class ControlledTable extends PureComponent visibleColumns } = this.props; - const isLoading = dataLoading(loading_state); - const fragmentClasses = [ [ fixed_rows && fixed_columns ? 'dash-fixed-row dash-fixed-column' : '', @@ -771,7 +768,7 @@ export default class ControlledTable extends PureComponent ...(virtualized.data.length ? [] : ['dash-no-data']), ...(filter_action !== TableAction.None ? [] : ['dash-no-filter']), ...(fill_width ? ['dash-fill-width'] : []), - ...(isLoading ? ['dash-loading'] : []) + ...(loading_state ? ['dash-loading'] : []) ]; const containerClasses = ['dash-spreadsheet-container', ...classes]; diff --git a/src/dash-table/components/Table/index.tsx b/src/dash-table/components/Table/index.tsx index f20893e7a..927fd3386 100644 --- a/src/dash-table/components/Table/index.tsx +++ b/src/dash-table/components/Table/index.tsx @@ -26,6 +26,7 @@ import derivedFilterMap from 'dash-table/derived/filter/map'; import controlledPropsHelper from './controlledPropsHelper'; import derivedPropsHelper from './derivedPropsHelper'; +import DOM from 'core/browser/DOM'; const DERIVED_REGEX = /^derived_/; @@ -49,24 +50,42 @@ export default class Table extends Component { - const { workFilter: { map: currentMap, value } } = state; - - if (value !== nextProps.filter_query) { - const map = this.filterMap( - currentMap, - nextProps.filter_query, - nextProps.visibleColumns - ); - - return map !== currentMap ? { workFilter: { map, value} } : null; - } else { - return null; + const { applyFocus: currentApplyFocus, workFilter: { map: currentMap, value } } = state; + + const nextState: Partial = {}; + + // state for filter + if (nextProps.filter_query !== this.props.filter_query) { + if (value !== nextProps.filter_query) { + const map = this.filterMap( + currentMap, + nextProps.filter_query, + nextProps.visibleColumns + ); + + if (map !== currentMap) { + nextState.workFilter = { map, value }; + } + } + } + + // state for applying focus + if (nextProps.active_cell !== this.props.active_cell) { + nextState.applyFocus = true; + } else if (nextProps.loading_state !== this.props.loading_state) { + const activeElement = document.activeElement as HTMLElement; + const tdElement = DOM.getFirstParentOfType(activeElement, 'td'); + const tableElement = DOM.getParentById(tdElement, this.props.id); + + nextState.applyFocus = !!tableElement; } + + if (nextState.applyFocus === currentApplyFocus) { + delete nextState.applyFocus; + } + + return R.keysIn(nextState).length ? nextState as any : null; }); } diff --git a/src/dash-table/components/Table/props.ts b/src/dash-table/components/Table/props.ts index fe380e40a..6d727a791 100644 --- a/src/dash-table/components/Table/props.ts +++ b/src/dash-table/components/Table/props.ts @@ -84,7 +84,7 @@ export interface ICellCoordinates { export type ColumnId = string; export type Columns = IColumn[]; export type Data = Datum[]; -export type Datum = IDatumObject | any; +export type Datum = IDatumObject | any; export type Indices = number[]; export type RowId = string | number; export type SelectedCells = ICellCoordinates[]; @@ -172,7 +172,7 @@ export interface IDatetimeColumn extends ITypeColumn { export interface IBaseColumn { clearable?: boolean | boolean[] | 'first' | 'last'; - deletable?: boolean | boolean[] | 'first' |'last'; + deletable?: boolean | boolean[] | 'first' | 'last'; editable: boolean; hideable?: boolean | boolean[] | 'first' | 'last'; renamable?: boolean | boolean[] | 'first' | 'last'; @@ -256,6 +256,7 @@ export interface IUSerInterfaceTooltip { export interface IState { activeMenu?: 'show/hide'; + applyFocus?: boolean; currentTooltip?: IUSerInterfaceTooltip; forcedResizeOnly: boolean; rawFilterQuery: string; @@ -410,6 +411,7 @@ export type SanitizedProps = Omit, 'locale_format'>, @@ -429,8 +431,6 @@ export type ControlledTableProps = SanitizedProps & IState & { virtual: IDerivedData; virtual_selected_rows: Indices; virtualized: IVirtualizedDerivedData; - - loading_state: ILoadingState | undefined; }; export type SetFilter = ( @@ -462,6 +462,7 @@ export type HeaderFactoryProps = ControlledTableProps & { export interface ICellFactoryProps { active_cell: ICellCoordinates; + applyFocus?: boolean; dropdown: StaticDropdowns; dropdown_conditional: ConditionalDropdowns; dropdown_data: DataDropdowns; @@ -474,6 +475,7 @@ export interface ICellFactoryProps { fixed_rows: number; id: string; is_focused?: boolean; + loading_state: boolean; paginator: IPaginator; row_deletable: boolean; row_selectable: Selection; @@ -498,6 +500,4 @@ export interface ICellFactoryProps { virtualization: boolean; virtualized: IVirtualizedDerivedData; visibleColumns: Columns; - - loading_state?: ILoadingState; } diff --git a/src/dash-table/dash/Sanitizer.ts b/src/dash-table/dash/Sanitizer.ts index f6609504a..72c6d618d 100644 --- a/src/dash-table/dash/Sanitizer.ts +++ b/src/dash-table/dash/Sanitizer.ts @@ -18,6 +18,7 @@ import { } from 'dash-table/components/Table/props'; import headerRows from 'dash-table/derived/header/headerRows'; import resolveFlag from 'dash-table/derived/cell/resolveFlag'; +import dataLoading from 'dash-table/derived/table/data_loading'; const D3_DEFAULT_LOCALE: INumberLocale = { symbol: ['$', ''], @@ -81,8 +82,8 @@ export default class Sanitizer { const visibleColumns = this.getVisibleColumns(columns, props.hidden_columns); let headerFormat = props.export_headers; - if (props.export_format === ExportFormat.Xlsx && R.isNil(headerFormat)) { - headerFormat = ExportHeaders.Names; + if (props.export_format === ExportFormat.Xlsx && R.isNil(headerFormat)) { + headerFormat = ExportHeaders.Names; } else if (props.export_format === ExportFormat.Csv && R.isNil(headerFormat)) { headerFormat = ExportHeaders.Ids; } @@ -92,6 +93,7 @@ export default class Sanitizer { export_headers: headerFormat, fixed_columns: getFixedColumns(props.fixed_columns, props.row_deletable, props.row_selectable), fixed_rows: getFixedRows(props.fixed_rows, props.columns, props.filter_action), + loading_state: dataLoading(props.loading_state), locale_format, visibleColumns }); diff --git a/src/dash-table/derived/cell/contents.tsx b/src/dash-table/derived/cell/contents.tsx index 51b5664ed..6af61a434 100644 --- a/src/dash-table/derived/cell/contents.tsx +++ b/src/dash-table/derived/cell/contents.tsx @@ -71,6 +71,7 @@ class Contents { return mapData( (datum, rowIndex) => mapRow( (column, columnIndex) => this.getContent( + false, false, isFocused, column, @@ -86,6 +87,7 @@ class Contents { get = memoizeOne(( contents: JSX.Element[][], activeCell: ICellCoordinates | undefined, + applyFocus: boolean, columns: Columns, data: Data, offset: IViewportOffset, @@ -110,6 +112,7 @@ class Contents { contents = shallowClone(contents); contents[i][j] = this.getContent( true, + applyFocus || false, isFocused, columns[j], dropdowns && dropdowns[i][j], @@ -123,7 +126,7 @@ class Contents { return contents; }); - private getContent(active: boolean, isFocused: boolean, column: IColumn, dropdown: IDropdown | undefined, columnIndex: number, rowIndex: number, datum: any, formatters: ((value: any) => any)[], data_loading: boolean) { + private getContent(active: boolean, applyFocus: boolean, isFocused: boolean, column: IColumn, dropdown: IDropdown | undefined, columnIndex: number, rowIndex: number, datum: any, formatters: ((value: any) => any)[], data_loading: boolean) { const className = [ ...(active ? ['input-active'] : []), @@ -138,6 +141,7 @@ class Contents { return ( { cy.visit('http://localhost:8084'); }); - it('does not permit editing when data are loading', () => { + it('prevents editing while loading', () => { // Table is editable DashTable .getCell(0, 0) @@ -25,24 +25,21 @@ describe('loading states uneditable', () => { .click() .find('.dash-input-cell-value-container > input').should('have.length', 0); - DOM.focused.type(`Hello${Key.Enter}`); - DashTable.getCell(1, 0, State.Any).click(); - DashTable .getCell(0, 0, State.Any) - .within(() => cy.get('.dash-cell-value') - .should('not.have.html', 'Hello')); + .within(() => cy.get('.dash-cell-value').should('not.have.html', 'Hello')); + + cy.get('#change-data-property').should('have.value', 'change_data'); cy.wait(5000); // Table is editable DashTable - .getCell(0, 0) + .getCell(0, 0, State.Ready) .click() .find('.dash-input-cell-value-container > input').should('have.length', 1); DOM.focused.type(`Hello${Key.Enter}`); - DashTable.getCell(1, 0).click(); DashTable .getCell(0, 0) @@ -50,6 +47,36 @@ describe('loading states uneditable', () => { .should('have.html', 'Hello')); }); + it('keeps focus on callback completion', () => { + cy.get('#change-data-property').click(); + DOM.focused.type(`change_data${Key.Enter}`); + + DashTable.getCell(0, 0, State.Loading).click(); + cy.wait(5000); + DashTable.getCell(0, 0, State.Ready); + + DOM.focused.type(`Hello${Key.Enter}`); + DashTable + .getCell(0, 0) + .within(() => cy.get('.dash-cell-value') + .should('have.html', 'Hello')); + }); + + it('does not steal focus on callback completion', () => { + DashTable.getCell(0, 0, State.Ready).click(); + + cy.get('#change-data-property').click(); + DOM.focused.type(`change_data${Key.Enter}`); + + DashTable.getCell(0, 0, State.Loading); + DOM.focused.should('have.id', 'change-data-property'); + + cy.wait(5000); + + DashTable.getCell(0, 0, State.Ready); + DOM.focused.should('have.id', 'change-data-property'); + }); + it('permits editing when a non-data prop is being changed', () => { // Table is editable DashTable diff --git a/tests/cypress/tests/server/select_props_test.ts b/tests/cypress/tests/server/select_props_test.ts index f018dd180..43e124ba8 100644 --- a/tests/cypress/tests/server/select_props_test.ts +++ b/tests/cypress/tests/server/select_props_test.ts @@ -115,7 +115,6 @@ describe('select row', () => { expectCellSelection([1, 2, 3], [3001, 3002, 3003], [0, 1], [0, 1], [2, 1], [2, 1]); // shrink the selection - DOM.focused.type(Key.Shift, { release: false }); DashTable.getCell(2, 1).click(); expectCellSelection([2, 3], [3002, 3003], [1], [1], [1, 0], [1, 0]); diff --git a/tests/cypress/tests/unit/exportUtils_tests.ts b/tests/cypress/tests/unit/exportUtils_tests.ts index 74c437e25..5a44f623c 100644 --- a/tests/cypress/tests/unit/exportUtils_tests.ts +++ b/tests/cypress/tests/unit/exportUtils_tests.ts @@ -1,6 +1,7 @@ import * as R from 'ramda'; import { ExportHeaders } from 'dash-table/components/Table/props'; +import 'xlsx'; /* Cheat and get the async resource pre-emptively */ import { transformMultiDimArray, getMergeRanges, createHeadings, createWorkbook } from 'dash-table/components/Export/utils'; describe('export', () => { @@ -18,27 +19,27 @@ describe('export', () => { const expectedArray = [['a'], ['b'], ['c'], ['d']]; expect(transformedArray).to.deep.equal(expectedArray); }); - it ('array with strings and strings array with same length', () => { + it('array with strings and strings array with same length', () => { const testedArray = ['a', ['b', 'c'], ['b', 'd']]; const transformedArray = transformMultiDimArray(testedArray, 2); const expectedArray = [['a', 'a'], ['b', 'c'], ['b', 'd']]; expect(transformedArray).to.deep.equal(expectedArray); }); - it ('2D strings array', () => { + it('2D strings array', () => { const testedArray = [['a', 'b', 'c'], ['b', 'c', 'd'], ['b', 'd', 'a']]; const transformedArray = transformMultiDimArray(testedArray, 3); const expectedArray = [['a', 'b', 'c'], ['b', 'c', 'd'], ['b', 'd', 'a']]; expect(transformedArray).to.deep.equal(expectedArray); }); - it ('multidimensional array', () => { + it('multidimensional array', () => { const testedArray = [['a', 'b'], ['b', 'c', 'd'], ['a', 'b', 'd', 'a']]; const transformedArray = transformMultiDimArray(testedArray, 4); const expectedArray = [['a', 'b', '', ''], ['b', 'c', 'd', ''], ['a', 'b', 'd', 'a']]; expect(transformedArray).to.deep.equal(expectedArray); }); - it ('multidimensional array with strings', () => { + it('multidimensional array with strings', () => { const testedArray = ['rows', ['a', 'b'], ['b', 'c', 'd'], ['a', 'b', 'd', 'a']]; const transformedArray = transformMultiDimArray(testedArray, 4); const expectedArray = [['rows', 'rows', 'rows', 'rows'], ['a', 'b', '', ''], ['b', 'c', 'd', ''], ['a', 'b', 'd', 'a']]; @@ -48,93 +49,113 @@ describe('export', () => { describe('getMergeRanges', () => { it('no merge', () => { - const testedArray = [['a', 'b', 'c', 'd'], - ['a', 'b', 'c', 'd'], - ['a', 'b', 'c', 'd']]; + const testedArray = [ + ['a', 'b', 'c', 'd'], + ['a', 'b', 'c', 'd'], + ['a', 'b', 'c', 'd'] + ]; const mergedRanges = getMergeRanges(testedArray); const expectedRanges = []; expect(mergedRanges).to.deep.equal(expectedRanges); }); it('duplicate values - no merge', () => { - const testedArray = [['a', 'b', 'c', 'a'], - ['a', 'b', 'c', 'a'], - ['a', 'b', 'c', 'a']]; + const testedArray = [ + ['a', 'b', 'c', 'a'], + ['a', 'b', 'c', 'a'], + ['a', 'b', 'c', 'a'] + ]; const mergedRanges = getMergeRanges(testedArray); const expectedRanges = []; expect(mergedRanges).to.deep.equal(expectedRanges); }); it('merge 2 cells right with a different value in between', () => { - const testedArray = [['a', 'b', 'c', 'd'], - ['a', 'b', 'a', 'a'], - ['a', 'b', 'c', 'd']]; + const testedArray = [ + ['a', 'b', 'c', 'd'], + ['a', 'b', 'a', 'a'], + ['a', 'b', 'c', 'd'] + ]; const mergedRanges = getMergeRanges(testedArray); - const expectedRanges = [{s: {r: 1, c: 2}, e: {r: 1, c: 3}}]; + const expectedRanges = [{ s: { r: 1, c: 2 }, e: { r: 1, c: 3 } }]; expect(mergedRanges).to.deep.equal(expectedRanges); }); it('merge 2 cells left with a different value in between', () => { - const testedArray = [['a', 'b', 'c', 'd'], - ['a', 'a', 'b', 'a'], - ['a', 'b', 'c', 'd']]; + const testedArray = [ + ['a', 'b', 'c', 'd'], + ['a', 'a', 'b', 'a'], + ['a', 'b', 'c', 'd'] + ]; const mergedRanges = getMergeRanges(testedArray); - const expectedRanges = [{s: {r: 1, c: 0}, e: {r: 1, c: 1}}]; + const expectedRanges = [{ s: { r: 1, c: 0 }, e: { r: 1, c: 1 } }]; expect(mergedRanges).to.deep.equal(expectedRanges); }); it('2 cells merge', () => { - const testedArray = [['a', 'b', 'c', 'd'], - ['a', 'a', 'c', 'd'], - ['a', 'b', 'c', 'd']]; + const testedArray = [ + ['a', 'b', 'c', 'd'], + ['a', 'a', 'c', 'd'], + ['a', 'b', 'c', 'd'] + ]; const mergedRanges = getMergeRanges(testedArray); - const expectedRanges = [{s: {r: 1, c: 0}, e: {r: 1, c: 1}}]; + const expectedRanges = [{ s: { r: 1, c: 0 }, e: { r: 1, c: 1 } }]; expect(mergedRanges).to.deep.equal(expectedRanges); }); it('3 cells merge', () => { - const testedArray = [['a', 'b', 'c', 'd'], - ['a', 'a', 'a', 'd'], - ['a', 'b', 'c', 'd']]; + const testedArray = [ + ['a', 'b', 'c', 'd'], + ['a', 'a', 'a', 'd'], + ['a', 'b', 'c', 'd'] + ]; const mergedRanges = getMergeRanges(testedArray); - const expectedRanges = [{s: {r: 1, c: 0}, e: {r: 1, c: 2}}]; + const expectedRanges = [{ s: { r: 1, c: 0 }, e: { r: 1, c: 2 } }]; expect(mergedRanges).to.deep.equal(expectedRanges); }); it('4 cells merge', () => { - const testedArray = [['a', 'b', 'c', 'd'], - ['a', 'a', 'a', 'a'], - ['a', 'b', 'c', 'd']]; + const testedArray = [ + ['a', 'b', 'c', 'd'], + ['a', 'a', 'a', 'a'], + ['a', 'b', 'c', 'd'] + ]; const mergedRanges = getMergeRanges(testedArray); - const expectedRanges = [{s: {r: 1, c: 0}, e: {r: 1, c: 3}}]; + const expectedRanges = [{ s: { r: 1, c: 0 }, e: { r: 1, c: 3 } }]; expect(mergedRanges).to.deep.equal(expectedRanges); }); it('2 cells merge, 4 cells merge - same value', () => { - const testedArray = [['a', 'a', 'c', 'd'], - ['a', 'a', 'a', 'a'], - ['a', 'b', 'c', 'd']]; + const testedArray = [ + ['a', 'a', 'c', 'd'], + ['a', 'a', 'a', 'a'], + ['a', 'b', 'c', 'd'] + ]; const mergedRanges = getMergeRanges(testedArray); const expectedRanges = [ - {s: {r: 0, c: 0}, e: {r: 0, c: 1}}, - {s: {r: 1, c: 0}, e: {r: 1, c: 3}} + { s: { r: 0, c: 0 }, e: { r: 0, c: 1 } }, + { s: { r: 1, c: 0 }, e: { r: 1, c: 3 } } ]; expect(mergedRanges).to.deep.equal(expectedRanges); }); it('2 cells merge, 4 cells merge, 3 cells merge - same value', () => { - const testedArray = [['a', 'a', 'c', 'd'], - ['a', 'a', 'a', 'a'], - ['a', 'a', 'a', 'd']]; + const testedArray = [ + ['a', 'a', 'c', 'd'], + ['a', 'a', 'a', 'a'], + ['a', 'a', 'a', 'd'] + ]; const mergedRanges = getMergeRanges(testedArray); const expectedRanges = [ - {s: {r: 0, c: 0}, e: {r: 0, c: 1}}, - {s: {r: 1, c: 0}, e: {r: 1, c: 3}}, - {s: {r: 2, c: 0}, e: {r: 2, c: 2}} + { s: { r: 0, c: 0 }, e: { r: 0, c: 1 } }, + { s: { r: 1, c: 0 }, e: { r: 1, c: 3 } }, + { s: { r: 2, c: 0 }, e: { r: 2, c: 2 } } ]; expect(mergedRanges).to.deep.equal(expectedRanges); }); it('table with same value', () => { - const testedArray = [['a', 'a', 'a', 'a'], - ['a', 'a', 'a', 'a'], - ['a', 'a', 'a', 'a']]; + const testedArray = [ + ['a', 'a', 'a', 'a'], + ['a', 'a', 'a', 'a'], + ['a', 'a', 'a', 'a'] + ]; const mergedRanges = getMergeRanges(testedArray); const expectedRanges = [ - {s: {r: 0, c: 0}, e: {r: 0, c: 3}}, - {s: {r: 1, c: 0}, e: {r: 1, c: 3}}, - {s: {r: 2, c: 0}, e: {r: 2, c: 3}} + { s: { r: 0, c: 0 }, e: { r: 0, c: 3 } }, + { s: { r: 1, c: 0 }, e: { r: 1, c: 3 } }, + { s: { r: 2, c: 0 }, e: { r: 2, c: 3 } } ]; expect(mergedRanges).to.deep.equal(expectedRanges); }); @@ -142,63 +163,81 @@ describe('export', () => { describe('createHeadings ', () => { it('strings 2D array input with same length for inner array', () => { - const input = [['a', 'b', 'c'], - ['d', 'e', 'f'], - ['g', 'h', 'i']]; + const input = [ + ['a', 'b', 'c'], + ['d', 'e', 'f'], + ['g', 'h', 'i'] + ]; const headings = createHeadings(input, 3); - const expectHeadings = [['a', 'd', 'g'], - ['b', 'e', 'h'], - ['c', 'f', 'i']]; + const expectHeadings = [ + ['a', 'd', 'g'], + ['b', 'e', 'h'], + ['c', 'f', 'i'] + ]; expect(headings).to.deep.equal(expectHeadings); }); it('strings 2D array input with one different length for inner array', () => { - const input = [['a', 'b', 'c'], - ['d', 'e', 'f'], - ['g', 'h', 'i', 'j']]; + const input = [ + ['a', 'b', 'c'], + ['d', 'e', 'f'], + ['g', 'h', 'i', 'j'] + ]; const headings = createHeadings(input, 4); - const expectHeadings = [['a', 'd', 'g'], - ['b', 'e', 'h'], - ['c', 'f', 'i'], - ['' , '', 'j']]; + const expectHeadings = [ + ['a', 'd', 'g'], + ['b', 'e', 'h'], + ['c', 'f', 'i'], + ['', '', 'j'] + ]; expect(headings).to.deep.equal(expectHeadings); }); it('strings 2D array input with multi different length for inner array', () => { - const input = [['a', 'b', 'c'], - ['d', 'e', 'f', '1'], - ['g', 'h', 'i', 'j', 'k']]; + const input = [ + ['a', 'b', 'c'], + ['d', 'e', 'f', '1'], + ['g', 'h', 'i', 'j', 'k'] + ]; const headings = createHeadings(input, 5); - const expectHeadings = [['a', 'd', 'g'], - ['b', 'e', 'h'], - ['c', 'f', 'i'], - ['' , '1', 'j'], - ['', '', 'k']]; + const expectHeadings = [ + ['a', 'd', 'g'], + ['b', 'e', 'h'], + ['c', 'f', 'i'], + ['', '1', 'j'], + ['', '', 'k'] + ]; expect(headings).to.deep.equal(expectHeadings); }); it('strings and string[] array with same length for inner array', () => { - const input = ['rows', - ['d', 'e', 'f'], - ['g', 'h', 'i']]; + const input = [ + 'rows', + ['d', 'e', 'f'], + ['g', 'h', 'i'] + ]; const headings = createHeadings(input, 3); - const expectHeadings = [['rows', 'd', 'g'], - ['rows', 'e', 'h'], - ['rows', 'f', 'i']]; + const expectHeadings = [ + ['rows', 'd', 'g'], + ['rows', 'e', 'h'], + ['rows', 'f', 'i'] + ]; expect(headings).to.deep.equal(expectHeadings); }); it('strings and string[] array with different length for inner array', () => { - const input = ['rows', - ['d', 'e', 'f', 'g'], - ['g', 'h', 'i']]; + const input = [ + 'rows', + ['d', 'e', 'f', 'g'], + ['g', 'h', 'i'] + ]; const headings = createHeadings(input, 4); - const expectHeadings = [['rows', 'd', 'g'], - ['rows', 'e', 'h'], - ['rows', 'f', 'i'], - ['rows', 'g', '']]; + const expectHeadings = [ + ['rows', 'd', 'g'], + ['rows', 'e', 'h'], + ['rows', 'f', 'i'], + ['rows', 'g', ''] + ]; expect(headings).to.deep.equal(expectHeadings); }); it('strings array', () => { - const input = ['1', - '2', - '3']; + const input = ['1', '2', '3']; const headings = createHeadings(input, 1); const expectHeadings = [['1', '2', '3']]; expect(headings).to.deep.equal(expectHeadings); @@ -231,32 +270,33 @@ describe('export', () => { const wsDisplay = await createWorkbook(Headings, data, columnID, ExportHeaders.Display, true); const wsDisplayNoMerge = await createWorkbook(Headings, data, columnID, ExportHeaders.Display, false); const expectedWS = { - A1: {t: 's', v: 'rows'}, - A2: {t: 's', v: 'rows'}, - A3: {t: 's', v: 'rows'}, - A4: {t: 's', v: 'rows'}, - A5: {t: 'n', v: 1}, - A6: {t: 'n', v: 2}, - A7: {t: 'n', v: 1}, - B1: {t: 's', v: 'rows'}, - B2: {t: 's', v: 'c'}, - B3: {t: 's', v: 'e'}, - B4: {t: 's', v: 'rows'}, - B5: {t: 'n', v: 2}, - B6: {t: 'n', v: 3}, - B7: {t: 'n', v: 2}, - C1: {t: 's', v: 'b'}, - C2: {t: 's', v: 'c'}, - C3: {t: 's', v: 'f'}, - C4: {t: 's', v: 'rows'}, - C5: {t: 'n', v: 3}, - C6: {t: 'n', v: 4}, - C7: {t: 'n', v: 3}}; + A1: { t: 's', v: 'rows' }, + A2: { t: 's', v: 'rows' }, + A3: { t: 's', v: 'rows' }, + A4: { t: 's', v: 'rows' }, + A5: { t: 'n', v: 1 }, + A6: { t: 'n', v: 2 }, + A7: { t: 'n', v: 1 }, + B1: { t: 's', v: 'rows' }, + B2: { t: 's', v: 'c' }, + B3: { t: 's', v: 'e' }, + B4: { t: 's', v: 'rows' }, + B5: { t: 'n', v: 2 }, + B6: { t: 'n', v: 3 }, + B7: { t: 'n', v: 2 }, + C1: { t: 's', v: 'b' }, + C2: { t: 's', v: 'c' }, + C3: { t: 's', v: 'f' }, + C4: { t: 's', v: 'rows' }, + C5: { t: 'n', v: 3 }, + C6: { t: 'n', v: 4 }, + C7: { t: 'n', v: 3 } + }; expectedWS['!ref'] = 'A1:C7'; const expectedWSDisplay = R.clone(expectedWS); - expectedWSDisplay['!merges'] = [ {s: {r: 0, c: 0}, e: {r: 0, c: 1}}, - {s: {r: 1, c: 1}, e: {r: 1, c: 2}}, - {s: {r: 3, c: 0}, e: {r: 3, c: 2}} ]; + expectedWSDisplay['!merges'] = [{ s: { r: 0, c: 0 }, e: { r: 0, c: 1 } }, + { s: { r: 1, c: 1 }, e: { r: 1, c: 2 } }, + { s: { r: 3, c: 0 }, e: { r: 3, c: 2 } }]; expect(wsName.Sheets.SheetJS).to.deep.equal(expectedWS); expect(wsDisplayNoMerge.Sheets.SheetJS).to.deep.equal(expectedWS); expect(wsDisplay.Sheets.SheetJS).to.deep.equal(expectedWSDisplay); @@ -264,61 +304,65 @@ describe('export', () => { it('create sheet with column ids as headers', async () => { const ws = await createWorkbook(Headings, data, columnID, ExportHeaders.Ids, true); const expectedWS = { - A1: {t: 's', v: 'col1'}, - A2: {t: 'n', v: 1}, - A3: {t: 'n', v: 2}, - A4: {t: 'n', v: 1}, - B1: {t: 's', v: 'col2'}, - B2: {t: 'n', v: 2}, - B3: {t: 'n', v: 3}, - B4: {t: 'n', v: 2}, - C1: {t: 's', v: 'col4'}, - C2: {t: 'n', v: 3}, - C3: {t: 'n', v: 4}, - C4: {t: 'n', v: 3}}; + A1: { t: 's', v: 'col1' }, + A2: { t: 'n', v: 1 }, + A3: { t: 'n', v: 2 }, + A4: { t: 'n', v: 1 }, + B1: { t: 's', v: 'col2' }, + B2: { t: 'n', v: 2 }, + B3: { t: 'n', v: 3 }, + B4: { t: 'n', v: 2 }, + C1: { t: 's', v: 'col4' }, + C2: { t: 'n', v: 3 }, + C3: { t: 'n', v: 4 }, + C4: { t: 'n', v: 3 } + }; expectedWS['!ref'] = 'A1:C4'; expect(ws.Sheets.SheetJS).to.deep.equal(expectedWS); }); it('create sheet with no headers', async () => { const ws = await createWorkbook([], data, columnID, ExportHeaders.None, true); const expectedWS = { - A1: {t: 'n', v: 1}, - A2: {t: 'n', v: 2}, - A3: {t: 'n', v: 1}, - B1: {t: 'n', v: 2}, - B2: {t: 'n', v: 3}, - B3: {t: 'n', v: 2}, - C1: {t: 'n', v: 3}, - C2: {t: 'n', v: 4}, - C3: {t: 'n', v: 3}}; + A1: { t: 'n', v: 1 }, + A2: { t: 'n', v: 2 }, + A3: { t: 'n', v: 1 }, + B1: { t: 'n', v: 2 }, + B2: { t: 'n', v: 3 }, + B3: { t: 'n', v: 2 }, + C1: { t: 'n', v: 3 }, + C2: { t: 'n', v: 4 }, + C3: { t: 'n', v: 3 } + }; expectedWS['!ref'] = 'A1:C3'; expect(ws.Sheets.SheetJS).to.deep.equal(expectedWS); }); it('create sheet with undefined column for clearable columns', async () => { const newData = [ - {col2: 2, col4: 3}, - {col2: 3, col4: 4}, - {col2: 2, col4: 3} + { col2: 2, col4: 3 }, + { col2: 3, col4: 4 }, + { col2: 2, col4: 3 } ]; const ws = await createWorkbook(Headings, newData, columnID, ExportHeaders.Display, false); - const expectedWS = {A1: {t: 's', v: 'rows'}, - A2: {t: 's', v: 'rows'}, - A3: {t: 's', v: 'rows'}, - A4: {t: 's', v: 'rows'}, - B1: {t: 's', v: 'rows'}, - B2: {t: 's', v: 'c'}, - B3: {t: 's', v: 'e'}, - B4: {t: 's', v: 'rows'}, - B5: {t: 'n', v: 2}, - B6: {t: 'n', v: 3}, - B7: {t: 'n', v: 2}, - C1: {t: 's', v: 'b'}, - C2: {t: 's', v: 'c'}, - C3: {t: 's', v: 'f'}, - C4: {t: 's', v: 'rows'}, - C5: {t: 'n', v: 3}, - C6: {t: 'n', v: 4}, - C7: {t: 'n', v: 3}}; + const expectedWS = { + A1: { t: 's', v: 'rows' }, + A2: { t: 's', v: 'rows' }, + A3: { t: 's', v: 'rows' }, + A4: { t: 's', v: 'rows' }, + B1: { t: 's', v: 'rows' }, + B2: { t: 's', v: 'c' }, + B3: { t: 's', v: 'e' }, + B4: { t: 's', v: 'rows' }, + B5: { t: 'n', v: 2 }, + B6: { t: 'n', v: 3 }, + B7: { t: 'n', v: 2 }, + C1: { t: 's', v: 'b' }, + C2: { t: 's', v: 'c' }, + C3: { t: 's', v: 'f' }, + C4: { t: 's', v: 'rows' }, + C5: { t: 'n', v: 3 }, + C6: { t: 'n', v: 4 }, + C7: { t: 'n', v: 3 } + }; expectedWS['!ref'] = 'A1:C7'; expect(ws.Sheets.SheetJS).to.deep.equal(expectedWS); }); diff --git a/webpack.test.config.js b/webpack.test.config.js index 4d381c983..058a9f8c3 100644 --- a/webpack.test.config.js +++ b/webpack.test.config.js @@ -1,4 +1,5 @@ const options = { + entry: ['@babel/polyfill'], ts: { transpileOnly: true }, diff --git a/webpack.test.standalone.config.js b/webpack.test.standalone.config.js index 67f2d692d..e44f128e4 100644 --- a/webpack.test.standalone.config.js +++ b/webpack.test.standalone.config.js @@ -1,17 +1,17 @@ const options = { + entry: ['@babel/polyfill'], ts: { transpileOnly: true }, preprocessor: { - variables: { + definitions: ['TEST', 'TEST_COPY_PASTE'], + variable: { mode: 'eager' - }, - definitions: ['TEST', 'TEST_COPY_PASTE'] + } }, mode: 'development' }; let config = require('./.config/webpack/base.js')(options); -delete config.plugins; module.exports = config; \ No newline at end of file