diff --git a/.github/workflows/chromatic.yml b/.github/workflows/chromatic.yml
new file mode 100644
index 000000000..773e1ad92
--- /dev/null
+++ b/.github/workflows/chromatic.yml
@@ -0,0 +1,34 @@
+name: Chromatic
+
+on: push
+
+jobs:
+ chromatic-deployment:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+
+ - uses: actions/setup-node@v2
+ with:
+ node-version: 16.14.2
+
+ - name: Cache pnpm modules
+ uses: actions/cache@v2
+ with:
+ path: ~/.pnpm-store
+ key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
+ restore-keys: |
+ ${{ runner.os }}-
+
+ - uses: pnpm/action-setup@v2
+ with:
+ version: 6
+ run_install: |
+ - args: [--frozen-lockfile]
+
+ - name: Publish to Chromatic
+ uses: chromaui/action@v1
+ with:
+ projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
diff --git a/.gitignore b/.gitignore
index f3932ff6f..21cd9bd74 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,6 +27,7 @@ cypress/screenshots/
# storybook
.storybook.out
.cache/
+build-storybook.log
# logs
yarn-error.log
diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx
index 8cbd973d4..113dbc616 100644
--- a/.storybook/preview.tsx
+++ b/.storybook/preview.tsx
@@ -2,12 +2,18 @@ import '@atlaskit/css-reset';
import React from 'react';
import { withPerformance } from 'storybook-addon-performance';
+import { resetData } from '../stories/src/data';
import GlobalStyles from './custom-decorators/global-styles';
import welcomeMessage from './welcome-message';
welcomeMessage();
export const decorators = [
+ (Story: React.ElementType, { id }: { id: string }) => {
+ resetData(id);
+
+ return ;
+ },
(Story: React.ElementType): React.ReactElement => (
diff --git a/.storybook/tsconfig.json b/.storybook/tsconfig.json
index a32dd4f23..06bc9649f 100644
--- a/.storybook/tsconfig.json
+++ b/.storybook/tsconfig.json
@@ -1,4 +1,10 @@
{
"extends": "../tsconfig.json",
- "include": ["**/*"]
+ "include": ["**/*"],
+ "compilerOptions": {
+ "baseUrl": ".",
+ "paths": {
+ "@react-forked/dnd": ["../src/index.ts"]
+ }
+ },
}
diff --git a/.storybook/typings.d.ts b/.storybook/typings.d.ts
index 3623b38e0..14461e25e 100644
--- a/.storybook/typings.d.ts
+++ b/.storybook/typings.d.ts
@@ -1,3 +1,8 @@
+declare module '*.png' {
+ const src: string;
+ export default src;
+}
+
declare module '*.svg' {
const src: string;
export default src;
diff --git a/cypress/integration/reorder.spec.ts b/cypress/integration/reorder.spec.ts
index 900c16b74..10a2d1b0d 100644
--- a/cypress/integration/reorder.spec.ts
+++ b/cypress/integration/reorder.spec.ts
@@ -9,8 +9,8 @@ describe('reorder', () => {
it('should reorder within a list', () => {
// order: 1, 2
- cy.get(getHandleSelector()).eq(0).as('first').should('contain', 'id:1');
- cy.get(getHandleSelector()).eq(1).should('contain', 'id:2');
+ cy.get(getHandleSelector()).eq(0).as('first').should('contain', 'id:G1');
+ cy.get(getHandleSelector()).eq(1).should('contain', 'id:G2');
// reorder operation
cy.get('@first')
@@ -25,11 +25,11 @@ describe('reorder', () => {
// order now 2, 1
// note: not using get aliases as they where returning incorrect results
- cy.get(getHandleSelector()).eq(0).should('contain', 'id:2');
+ cy.get(getHandleSelector()).eq(0).should('contain', 'id:G2');
- cy.get(getHandleSelector()).eq(1).should('contain', 'id:1');
+ cy.get(getHandleSelector()).eq(1).should('contain', 'id:G1');
// element should maintain focus post drag
- cy.focused().should('contain', 'id:1');
+ cy.focused().should('contain', 'id:G1');
});
});
diff --git a/package.json b/package.json
index 20a40c14c..d1d4866e9 100644
--- a/package.json
+++ b/package.json
@@ -37,6 +37,7 @@
"prettier_target": "*.{js,jsx,ts,tsx,md,json} src/**/*.{js,jsx,ts,tsx,md,json} test/**/*.{js,jsx,ts,tsx,md,json} docs/**/*.{js,jsx,ts,tsx,md,json} stories/**/*.{js,jsx,ts,tsx,md,json} cypress/**/*.{js,jsx,ts,tsx,md,json} csp-server/**/*.{js,jsx,ts,tsx,md,json}"
},
"scripts": {
+ "chromatic": "chromatic --project-token=f92123f238de",
"prepare": "husky install",
"release": "cross-env SKIP_PREPARE_COMMIT_MSG=true release-it",
"test:accessibility": "lighthouse http://localhost:9002/iframe.html?id=single-vertical-list--basic --no-enable-error-reporting --config-path=lighthouse.config.js --chrome-flags='--headless' --output=json --output=html --output-path=./test-reports/lighthouse/a11y.json && node a11y-audit-parse.js",
@@ -123,6 +124,7 @@
"@types/react-redux": "7.1.23",
"@types/react-virtualized": "9.21.20",
"@types/react-window": "1.8.5",
+ "@types/seedrandom": "3.0.2",
"@typescript-eslint/eslint-plugin": "5.15.0",
"@typescript-eslint/parser": "5.15.0",
"@wojtekmaj/enzyme-adapter-react-17": "0.6.6",
@@ -181,6 +183,7 @@
"rollup-plugin-dts": "4.2.0",
"rollup-plugin-size-snapshot": "0.12.0",
"rollup-plugin-terser": "7.0.2",
+ "seedrandom": "3.0.5",
"storybook-addon-performance": "0.16.1",
"styled-components": "5.3.3",
"stylelint": "14.6.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c2f4d6e19..da75975c2 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -51,6 +51,7 @@ specifiers:
'@types/react-redux': 7.1.23
'@types/react-virtualized': 9.21.20
'@types/react-window': 1.8.5
+ '@types/seedrandom': 3.0.2
'@typescript-eslint/eslint-plugin': 5.15.0
'@typescript-eslint/parser': 5.15.0
'@wojtekmaj/enzyme-adapter-react-17': 0.6.6
@@ -114,6 +115,7 @@ specifiers:
rollup-plugin-dts: 4.2.0
rollup-plugin-size-snapshot: 0.12.0
rollup-plugin-terser: 7.0.2
+ seedrandom: 3.0.5
storybook-addon-performance: 0.16.1
styled-components: 5.3.3
stylelint: 14.6.0
@@ -187,6 +189,7 @@ devDependencies:
'@types/react-redux': 7.1.23
'@types/react-virtualized': 9.21.20
'@types/react-window': 1.8.5
+ '@types/seedrandom': 3.0.2
'@typescript-eslint/eslint-plugin': 5.15.0_f2c49ce7d0e93ebcfdb4b7d25b131b28
'@typescript-eslint/parser': 5.15.0_eslint@8.11.0+typescript@4.6.2
'@wojtekmaj/enzyme-adapter-react-17': 0.6.6_fae758709a8810ba97b4c03852dde4d0
@@ -245,6 +248,7 @@ devDependencies:
rollup-plugin-dts: 4.2.0_rollup@2.70.1+typescript@4.6.2
rollup-plugin-size-snapshot: 0.12.0_rollup@2.70.1
rollup-plugin-terser: 7.0.2_rollup@2.70.1
+ seedrandom: 3.0.5
storybook-addon-performance: 0.16.1_f456dfc349ace84b0ea11d9e6e4ef3ab
styled-components: 5.3.3_react-dom@17.0.2+react@17.0.2
stylelint: 14.6.0
@@ -4514,6 +4518,10 @@ packages:
/@types/scheduler/0.16.2:
resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==}
+ /@types/seedrandom/3.0.2:
+ resolution: {integrity: sha512-YPLqEOo0/X8JU3rdiq+RgUKtQhQtrppE766y7vMTu8dGML7TVtZNiiiaC/hhU9Zqw9UYopXxhuWWENclMVBwKQ==}
+ dev: true
+
/@types/serve-static/1.13.10:
resolution: {integrity: sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==}
dependencies:
@@ -14849,6 +14857,10 @@ packages:
ajv-keywords: 3.5.2_ajv@6.12.6
dev: true
+ /seedrandom/3.0.5:
+ resolution: {integrity: sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==}
+ dev: true
+
/semver-diff/3.1.1:
resolution: {integrity: sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==}
engines: {node: '>=8'}
diff --git a/stories/1-single-vertical-list.stories.tsx b/stories/1-single-vertical-list.stories.tsx
index 3322c1241..3dd542c6b 100644
--- a/stories/1-single-vertical-list.stories.tsx
+++ b/stories/1-single-vertical-list.stories.tsx
@@ -2,13 +2,13 @@ import React from 'react';
import { storiesOf } from '@storybook/react';
import styled from '@emotion/styled';
import QuoteApp from './src/vertical/quote-app';
-import { quotes, getQuotes } from './src/data';
+import { getQuotes } from './src/data';
import { grid } from './src/constants';
-const data = {
- small: quotes,
- medium: getQuotes(40),
- large: getQuotes(500),
+const generateData = {
+ small: () => getQuotes(),
+ medium: () => getQuotes(40),
+ large: () => getQuotes(500),
};
const ScrollContainer = styled.div`
@@ -27,11 +27,17 @@ const Title = styled.h4`
`;
storiesOf('single vertical list', module)
- .add('basic', () => )
- .add('large data set', () => )
+ .add('basic', () => )
+ .add('large data set', () => , {
+ chromatic: {
+ // This is to make sure we do not reach
+ // the 25,000,000px limit of the snapshot.
+ viewports: [320],
+ },
+ })
.add('Droppable is a scroll container', () => (
(
(
List is within a larger scroll container
-
+
))
.add('with combine enabled', () => (
-
+
));
diff --git a/stories/10-table.stories.tsx b/stories/10-table.stories.tsx
index 8885b048d..d035685e4 100644
--- a/stories/10-table.stories.tsx
+++ b/stories/10-table.stories.tsx
@@ -4,12 +4,14 @@ import WithDimensionLocking from './src/table/with-dimension-locking';
import WithFixedColumns from './src/table/with-fixed-columns';
import WithPortal from './src/table/with-portal';
import WithClone from './src/table/with-clone';
-import { quotes } from './src/data';
+import { getQuotes } from './src/data';
storiesOf('Tables', module)
- .add('with fixed width columns', () => )
+ .add('with fixed width columns', () => (
+
+ ))
.add('with dimension locking', () => (
-
+
))
- .add('with clone', () => )
- .add('with custom portal', () => );
+ .add('with clone', () => )
+ .add('with custom portal', () => );
diff --git a/stories/11-portal.stories.tsx b/stories/11-portal.stories.tsx
index ff937a4f2..ed3718715 100644
--- a/stories/11-portal.stories.tsx
+++ b/stories/11-portal.stories.tsx
@@ -1,8 +1,8 @@
import React from 'react';
import { storiesOf } from '@storybook/react';
import PortalApp from './src/portal/portal-app';
-import { quotes } from './src/data';
+import { getQuotes } from './src/data';
storiesOf('Portals', module).add('Using your own portal', () => (
-
+
));
diff --git a/stories/2-single-horizontal.stories.tsx b/stories/2-single-horizontal.stories.tsx
index ec24c180f..ee013a559 100644
--- a/stories/2-single-horizontal.stories.tsx
+++ b/stories/2-single-horizontal.stories.tsx
@@ -2,25 +2,24 @@ import React from 'react';
import { storiesOf } from '@storybook/react';
import styled from '@emotion/styled';
import AuthorApp from './src/horizontal/author-app';
-import { quotes, getQuotes } from './src/data';
-import type { Quote } from './src/types';
+import { getQuotes } from './src/data';
-const bigData: Quote[] = getQuotes(30);
+const generateBigData = () => getQuotes(30);
const WideWindow = styled.div`
width: 120vw;
`;
storiesOf('single horizontal list', module)
- .add('simple', () => )
+ .add('simple', () => )
.add('with combine enabled', () => (
-
+
))
.add('with overflow scroll', () => (
-
+
))
.add('with window scroll and overflow scroll', () => (
-
+
));
diff --git a/stories/3-board.stories.stories.tsx b/stories/3-board.stories.stories.tsx
index ea091cb01..c062f5ff6 100644
--- a/stories/3-board.stories.stories.tsx
+++ b/stories/3-board.stories.stories.tsx
@@ -4,17 +4,17 @@ import Board from './src/board/board';
import { authorQuoteMap, generateQuoteMap } from './src/data';
const data = {
- medium: generateQuoteMap(100),
- large: generateQuoteMap(500),
+ medium: () => generateQuoteMap(100),
+ large: () => generateQuoteMap(500),
};
storiesOf('board', module)
.add('simple', () => )
.add('dragging a clone', () => )
- .add('medium data set', () => )
- .add('large data set', () => )
+ .add('medium data set', () => )
+ .add('large data set', () => )
.add('long lists in a short container', () => (
-
+
))
.add('scrollable columns', () => (
diff --git a/stories/40-programmatic.stories.tsx b/stories/40-programmatic.stories.tsx
index 6e1242369..c3579875a 100644
--- a/stories/40-programmatic.stories.tsx
+++ b/stories/40-programmatic.stories.tsx
@@ -2,8 +2,10 @@ import React from 'react';
import { storiesOf } from '@storybook/react';
import WithControls from './src/programmatic/with-controls';
import Runsheet from './src/programmatic/runsheet';
-import { quotes } from './src/data';
+import { getQuotes } from './src/data';
storiesOf('Programmatic dragging', module)
- .add('with controls', () => )
- .add('with runsheet', () => );
+ .add('with controls', () => (
+
+ ))
+ .add('with runsheet', () => );
diff --git a/stories/45-virtual.stories.tsx b/stories/45-virtual.stories.tsx
index fe341f19a..2a2e3430a 100644
--- a/stories/45-virtual.stories.tsx
+++ b/stories/45-virtual.stories.tsx
@@ -14,6 +14,14 @@ storiesOf('Virtual: react-window', module)
storiesOf('Virtual: react-virtualized', module)
.add('list', () => )
.add('board', () => )
- .add('window list', () => (
-
- ));
+ .add(
+ 'window list',
+ () => ,
+ {
+ chromatic: {
+ // This is to make sure we do not reach
+ // the 25,000,000px limit of the snapshot.
+ viewports: [320],
+ },
+ },
+ );
diff --git a/stories/5-multiple-vertical-lists.stories.tsx b/stories/5-multiple-vertical-lists.stories.tsx
index fd5a8658b..96f7d2328 100644
--- a/stories/5-multiple-vertical-lists.stories.tsx
+++ b/stories/5-multiple-vertical-lists.stories.tsx
@@ -3,7 +3,7 @@ import { storiesOf } from '@storybook/react';
import QuoteApp from './src/multiple-vertical/quote-app';
import { getQuotes } from './src/data';
-const quoteMap = {
+const generateQuoteMap = () => ({
alpha: getQuotes(7),
beta: getQuotes(3),
gamma: getQuotes(7),
@@ -14,8 +14,8 @@ const quoteMap = {
theta: getQuotes(5),
iota: getQuotes(20),
kappa: getQuotes(5),
-};
+});
storiesOf('multiple vertical lists', module).add('stress test', () => (
-
+
));
diff --git a/stories/6-multiple-horizontal-lists.stories.tsx b/stories/6-multiple-horizontal-lists.stories.tsx
index e8654c078..f317b3d0d 100644
--- a/stories/6-multiple-horizontal-lists.stories.tsx
+++ b/stories/6-multiple-horizontal-lists.stories.tsx
@@ -3,12 +3,12 @@ import { storiesOf } from '@storybook/react';
import QuoteApp from './src/multiple-horizontal/quote-app';
import { getQuotes } from './src/data';
-const quoteMap = {
+const generateQuoteMap = () => ({
alpha: getQuotes(20),
beta: getQuotes(18),
gamma: getQuotes(22),
-};
+});
storiesOf('multiple horizontal lists', module).add('stress test', () => (
-
+
));
diff --git a/stories/src/data.ts b/stories/src/data.ts
index 3c31d23f8..f33b9332c 100644
--- a/stories/src/data.ts
+++ b/stories/src/data.ts
@@ -1,4 +1,5 @@
import { colors } from '@atlaskit/theme';
+import seedrandom from 'seedrandom';
import type { Author, Quote, QuoteMap } from './types';
import finnImg from '../static/media/finn-min.png';
import bmoImg from '../static/media/bmo-min.png';
@@ -117,29 +118,25 @@ export const quotes: Quote[] = [
];
// So we do not have any clashes with our hardcoded ones
-let idCount: number = quotes.length + 1;
+let idCount: number;
+let predictableMathRandom: seedrandom.PRNG;
-export const getQuotes = (count: number): Quote[] =>
- // eslint-disable-next-line no-restricted-syntax
- Array.from({ length: count }, (v, k) => k).map(() => {
- const random: Quote = quotes[Math.floor(Math.random() * quotes.length)];
-
- const custom: Quote = {
- ...random,
- id: `G${idCount++}`,
- };
+export const resetData = (seed: string) => {
+ idCount = 1;
+ predictableMathRandom = seedrandom(seed);
+};
- return custom;
- });
+resetData('base');
-export const getAuthors = (count: number): Author[] =>
+export const getQuotes = (count: number = quotes.length): Quote[] =>
// eslint-disable-next-line no-restricted-syntax
Array.from({ length: count }, (v, k) => k).map(() => {
- const random: Author = authors[Math.floor(Math.random() * authors.length)];
+ const random: Quote =
+ quotes[Math.floor(predictableMathRandom() * quotes.length)];
- const custom: Author = {
+ const custom: Quote = {
...random,
- id: `author-${idCount++}`,
+ id: `G${idCount++}`,
};
return custom;