Skip to content

Commit 0e8321f

Browse files
3.0 fixed columns and rows (#56)
* - refactor: isolate dash component layer from component implementation - duplicate component contract in TS * update for build js/py * - fix python component packaging regression - bump version to rc6 * Fix visual tests regression * (wip) refactor controlled table * @types * refactor table clipboard usage * clean up * rename * pr review fixes * fix bug in test script * fix test * update test script * fix tests * fix tests * tests -- remove async/await syntax * fix tests * - remove row component - 3 tables for fixed rows/columns and content - update TS props * remove test code * fix test * remove test / broken by Cypress.io * cypress version * fix cell selection test * fix percy tests * prevent useless cell updates once again * styling, copy/paste, navigation regressions * build, variables renamed * fix next/previous regression * fix test regressions * table styling regression * - fixed rows/columns regression testing + fixes - percy tests for fixed rows/columns * fix test? * fix test? * revert percy removal * - add runtime logger configuration override - fix scrolling issue in prod environment * - fix merged cells / hidden cells w/ fixed col & rows - additional visual tests for merged, fixed, hidden combo
1 parent 79e7380 commit 0e8321f

38 files changed

+1314
-1108
lines changed
+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
declare module 'sheetclip' {
2+
const value: any;
3+
export default value;
4+
}

packages/dash-table/dash_table/bundle.js

+3-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/dash-table/dash_table/demo.js

+3-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/dash-table/dash_table/metadata.json

+11-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"src/dash-table/components/Table.js": {
2+
"src/dash-table/Table.js": {
33
"description": "",
44
"displayName": "Table",
55
"methods": [],
@@ -134,6 +134,10 @@
134134
{
135135
"value": "'multi'",
136136
"computed": false
137+
},
138+
{
139+
"value": "false",
140+
"computed": false
137141
}
138142
]
139143
},
@@ -236,7 +240,11 @@
236240
"computed": false
237241
},
238242
{
239-
"value": "'none'",
243+
"value": "true",
244+
"computed": false
245+
},
246+
{
247+
"value": "false",
240248
"computed": false
241249
}
242250
]
@@ -639,7 +647,7 @@
639647
},
640648
"base_styles": {
641649
"defaultValue": {
642-
"value": "{\n numeric: {\n 'text-align': 'right',\n 'font-family': \"'Droid Sans Mono', Courier, monospace\",\n },\n\n string: {\n 'text-align': 'left',\n },\n\n input: {\n padding: 0,\n margin: 0,\n width: '80px',\n border: 'none',\n 'font-size': '1rem',\n },\n\n 'input-active': {\n outline: '#7FDBFF auto 3px',\n },\n\n table: {},\n\n thead: {},\n\n th: {},\n\n td: {},\n}",
650+
"value": "{\n numeric: {\n 'text-align': 'right',\n 'font-family': `'Droid Sans Mono', Courier, monospace`\n },\n\n string: {\n 'text-align': 'left'\n },\n\n input: {\n padding: 0,\n margin: 0,\n width: '80px',\n border: 'none',\n 'font-size': '1rem'\n },\n\n 'input-active': {\n outline: '#7FDBFF auto 3px'\n },\n\n table: {},\n\n thead: {},\n\n th: {},\n\n td: {}\n}",
643651
"computed": false
644652
},
645653
"required": false

packages/dash-table/dash_table/package.json

+8-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "dash-table",
3-
"version": "3.0.0rc5",
3+
"version": "3.0.0rc6",
44
"description": "Dash table",
55
"main": "build/index.js",
66
"scripts": {
@@ -16,14 +16,15 @@
1616
"private::lint.js": "eslint src",
1717
"private::lint.ts": "tslint --project . src/**/*.ts",
1818
"private::opentests": "cypress open",
19-
"private::runtests": "cypress run",
20-
"private::snapshots": "build-storybook && percy-storybook",
19+
"private::runtests": "cypress run --browser chrome",
20+
"private::test-e2e": "run-p --race private::host* private::runtests",
21+
"private::test-visual": "build-storybook && percy-storybook",
2122
"build.watch": "webpack-dev-server --content-base dash_table --mode development",
2223
"build:js-dev": "run-s \"private::build -- --mode development\"",
2324
"build:js": "run-s \"private::build -- --mode production\"",
24-
"build:py": "./extract-meta src/dash-table/components/Table.js > dash_table/metadata.json && cp package.json dash_table",
25+
"build:py": "./extract-meta src/dash-table/Table.js > dash_table/metadata.json && cp package.json dash_table",
2526
"lint": "run-s private::lint.js private::lint.ts",
26-
"test": "run-p --race private::host* private::runtests private::snapshots",
27+
"test": "run-s private::test-*",
2728
"test.watch": "run-p --race \"private::build -- --mode development --watch\" --race private::host* private::opentests"
2829
},
2930
"author": "Chris P <[email protected]",
@@ -42,13 +43,14 @@
4243
"@storybook/cli": "^4.0.0-alpha.16",
4344
"@storybook/react": "^4.0.0-alpha.16",
4445
"@types/ramda": "^0.25.36",
46+
"@types/react-select": "^1.2.1",
4547
"babel-core": "^6.26.3",
4648
"babel-eslint": "^8.2.3",
4749
"babel-loader": "^7.1.4",
4850
"babel-preset-env": "^1.7.0",
4951
"babel-preset-react": "^6.24.1",
5052
"css-loader": "^0.28.11",
51-
"cypress": "^3.0.3",
53+
"cypress": "^3.1.0",
5254
"eslint": "^4.19.1",
5355
"eslint-config-prettier": "^2.9.0",
5456
"eslint-plugin-import": "^2.12.0",

packages/dash-table/demo/App.js

+8-4
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22
import * as R from 'ramda';
33
import React, {Component} from 'react';
44
import PropTypes from 'prop-types';
5-
import {Table} from 'dash-table';
5+
import { Table } from 'dash-table';
66
import {mockData} from './data';
77
import { memoizeOne } from 'core/memoizer';
88

99
const clone = o => JSON.parse(JSON.stringify(o));
1010

11+
1112
class App extends Component {
1213
constructor() {
1314
super();
@@ -27,9 +28,9 @@ class App extends Component {
2728
editable: true,
2829
filtering: true,
2930
sorting: true,
30-
// n_fixed_rows: 3,
31-
// n_fixed_columns: 2,
32-
merge_duplicate_headers: true,
31+
n_fixed_rows: 3,
32+
n_fixed_columns: 2,
33+
merge_duplicate_headers: false,
3334
row_deletable: true,
3435
row_selectable: 'single',
3536
column_static_dropdown: [
@@ -41,6 +42,9 @@ class App extends Component {
4142
}))
4243
}
4344
],
45+
table_style: [
46+
{ selector: '.dash-spreadsheet.freeze-left', rule: 'width: 1000px' }
47+
]
4448
}
4549
};
4650

packages/dash-table/demo/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import App from './App';
44

55
import Logger, { DebugLevel, LogLevel } from 'core/Logger';
66

7-
Logger.setDebugLevel(DebugLevel.NONE);
7+
Logger.setDebugLevel(DebugLevel.DEBUG);
88
Logger.setLogLevel(LogLevel.WARNING);
99

1010
ReactDOM.render(<App />, document.getElementById('root'));

packages/dash-table/npm-shrinkwrap.json

+10-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/dash-table/package.json

+8-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "dash-table",
3-
"version": "3.0.0rc5",
3+
"version": "3.0.0rc6",
44
"description": "Dash table",
55
"main": "build/index.js",
66
"scripts": {
@@ -16,14 +16,15 @@
1616
"private::lint.js": "eslint src",
1717
"private::lint.ts": "tslint --project . src/**/*.ts",
1818
"private::opentests": "cypress open",
19-
"private::runtests": "cypress run",
20-
"private::snapshots": "build-storybook && percy-storybook",
19+
"private::runtests": "cypress run --browser chrome",
20+
"private::test-e2e": "run-p --race private::host* private::runtests",
21+
"private::test-visual": "build-storybook && percy-storybook",
2122
"build.watch": "webpack-dev-server --content-base dash_table --mode development",
2223
"build:js-dev": "run-s \"private::build -- --mode development\"",
2324
"build:js": "run-s \"private::build -- --mode production\"",
24-
"build:py": "./extract-meta src/dash-table/components/Table.js > dash_table/metadata.json && cp package.json dash_table",
25+
"build:py": "./extract-meta src/dash-table/Table.js > dash_table/metadata.json && cp package.json dash_table",
2526
"lint": "run-s private::lint.js private::lint.ts",
26-
"test": "run-p --race private::host* private::runtests private::snapshots",
27+
"test": "run-s private::test-*",
2728
"test.watch": "run-p --race \"private::build -- --mode development --watch\" --race private::host* private::opentests"
2829
},
2930
"author": "Chris P <[email protected]",
@@ -42,13 +43,14 @@
4243
"@storybook/cli": "^4.0.0-alpha.16",
4344
"@storybook/react": "^4.0.0-alpha.16",
4445
"@types/ramda": "^0.25.36",
46+
"@types/react-select": "^1.2.1",
4547
"babel-core": "^6.26.3",
4648
"babel-eslint": "^8.2.3",
4749
"babel-loader": "^7.1.4",
4850
"babel-preset-env": "^1.7.0",
4951
"babel-preset-react": "^6.24.1",
5052
"css-loader": "^0.28.11",
51-
"cypress": "^3.0.3",
53+
"cypress": "^3.1.0",
5254
"eslint": "^4.19.1",
5355
"eslint-config-prettier": "^2.9.0",
5456
"eslint-plugin-import": "^2.12.0",
+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
export default class Clipboard {
2+
public static set(value: string): void {
3+
const el = document.createElement('textarea');
4+
el.value = value;
5+
6+
// (Adapted from https://hackernoon.com/copying-text-to-clipboard-with-javascript-df4d4988697f)
7+
// Make it readonly to be tamper-proof
8+
el.setAttribute('readonly', '');
9+
// el.style.position = 'absolute';
10+
// Move outside the screen to make it invisible
11+
// el.style.left = '-9999px';
12+
// Append the <textarea> element to the HTML document
13+
document.body.appendChild(el);
14+
15+
// Check if there is any content selected previously
16+
let selected;
17+
if (document.getSelection().rangeCount > 0) {
18+
// Store selection if found
19+
selected = document.getSelection().getRangeAt(0);
20+
}
21+
22+
// Select the <textarea> content
23+
el.select();
24+
// Copy - only works as a result of a user action (e.g. click events)
25+
document.execCommand('copy');
26+
// Remove the <textarea> element
27+
document.body.removeChild(el);
28+
// If a selection existed before copying
29+
if (selected) {
30+
// Unselect everything on the HTML document
31+
document.getSelection().removeAllRanges();
32+
// Restore the original selection
33+
document.getSelection().addRange(selected);
34+
}
35+
}
36+
37+
public static get(ev: ClipboardEvent) {
38+
return ev.clipboardData ?
39+
ev.clipboardData.getData('text/plain') :
40+
undefined;
41+
}
42+
}

packages/dash-table/src/core/Stylesheet.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import Logger from 'core/Logger';
2+
13
interface IRule {
24
cssText: string;
35
selectorText: string;
@@ -84,13 +86,15 @@ export default class Stylesheet {
8486

8587
const result = this.stylesheet.findRule(selector);
8688
if (result) {
87-
if (result.rule.cssText === css) {
89+
90+
if (result.rule.cssText === css || result.rule.cssText === `${selector} { ${css} }`) {
8891
return;
8992
} else {
9093
this.stylesheet.deleteRule(result.index);
9194
}
9295
}
9396

9497
this.stylesheet.addRule(selector, css);
98+
Logger.debug('stylesheet', selector, css);
9599
}
96100
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { DebugLevel, LogLevel } from 'core/Logger';
2+
import CookieStorage from 'core/storage/Cookie';
3+
4+
const DASH_DEBUG = 'dash_debug';
5+
const DASH_LOG = 'dash_log';
6+
7+
export default class Environment {
8+
private static get searchParams() {
9+
return new URL(window.location.href).searchParams;
10+
}
11+
12+
public static get debugLevel(): DebugLevel {
13+
const debug = this.searchParams.get(DASH_DEBUG) || CookieStorage.get(DASH_DEBUG);
14+
15+
return debug ?
16+
(DebugLevel as any)[debug] || DebugLevel.NONE :
17+
DebugLevel.NONE;
18+
}
19+
20+
public static get logLevel(): LogLevel {
21+
const log = this.searchParams.get(DASH_LOG) || CookieStorage.get(DASH_LOG);
22+
23+
return log ?
24+
(LogLevel as any)[log] || LogLevel.ERROR :
25+
LogLevel.ERROR;
26+
}
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export default (seed: number | undefined = undefined) => {
2+
let lcg = (a: number) => a * 48271 % 2147483647;
3+
4+
let safeSeed = seed !== undefined ? lcg(seed) : lcg(Math.random());
5+
6+
return () => (safeSeed = lcg(safeSeed)) / 2147483648;
7+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
const __1day = 86400 * 1000;
2+
const __20years = 86400 * 1000 * 365 * 20;
3+
4+
export default class CookieStorage {
5+
public static delete(id: string, domain: string = '', path: string = '/') {
6+
let expires = new Date((new Date().getTime() - __1day)).toUTCString();
7+
8+
document.cookie = `${id}=;expires=${expires};domain=${domain};path=${path}`;
9+
}
10+
11+
public static get(id: string) {
12+
if (!id.length) {
13+
return;
14+
}
15+
16+
id = id.toLowerCase();
17+
18+
let cookies = document.cookie.split(';').map(cookie => {
19+
let fragments = cookie.split('=');
20+
21+
return {
22+
id: fragments[0].trim(),
23+
value: fragments[1]
24+
};
25+
});
26+
27+
return (cookies.find(cookie => id === cookie.id.toLocaleLowerCase()) || {} as any).value;
28+
}
29+
30+
public static set(id: string, value: string, domain: string = '', path: string = '/') {
31+
let expires = new Date((new Date().getTime() + __20years)).toUTCString();
32+
33+
let entry = `${id}=${value};expires=${expires};domain=${domain};path=${path}`;
34+
35+
if (CookieStorage.get(id)) {
36+
CookieStorage.delete(id, domain, path);
37+
}
38+
39+
document.cookie = entry;
40+
}
41+
}

0 commit comments

Comments
 (0)