diff --git a/.eslintignore b/.eslintignore
index 564cfdfb14d2a..5e4165322a118 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -4,6 +4,7 @@ shells/browser/chrome/build
shells/browser/firefox/build
shells/browser/shared/build
shells/dev/dist
+packages/react-devtools-core/dist
vendor
*.js.snap
diff --git a/package.json b/package.json
index 18c5527081a3d..f5dd64b0dee18 100644
--- a/package.json
+++ b/package.json
@@ -63,7 +63,7 @@
"test:chrome": "node ./shells/browser/chrome/test",
"test:firefox": "node ./shells/browser/firefox/test",
"test:standalone": "cd packages/react-devtools && yarn start",
- "typecheck": "flow check"
+ "typecheck": "flow check --show-all-errors"
},
"devEngines": {
"node": "10.x || 11.x"
@@ -119,7 +119,7 @@
"fbjs": "0.5.1",
"fbjs-scripts": "0.7.0",
"firefox-profile": "^1.0.2",
- "flow-bin": "^0.97.0",
+ "flow-bin": "^0.103.0",
"fs-extra": "^3.0.1",
"gh-pages": "^1.0.0",
"html2canvas": "^1.0.0-alpha.12",
diff --git a/packages/react-devtools-core/src/backend.js b/packages/react-devtools-core/src/backend.js
index f76659180aa56..11a5dde7c96cf 100644
--- a/packages/react-devtools-core/src/backend.js
+++ b/packages/react-devtools-core/src/backend.js
@@ -8,6 +8,7 @@ import { __DEBUG__ } from 'src/constants';
import setupNativeStyleEditor from 'src/backend/NativeStyleEditor/setupNativeStyleEditor';
import { getDefaultComponentFilters } from 'src/utils';
+import type { BackendBridge } from 'src/bridge';
import type { ComponentFilter } from 'src/types';
import type { DevToolsHook } from 'src/backend/types';
import type { ResolveNativeStyle } from 'src/backend/NativeStyleEditor/setupNativeStyleEditor';
@@ -64,7 +65,7 @@ export function connectToDevTools(options: ?ConnectOptions) {
return;
}
- let bridge: Bridge | null = null;
+ let bridge: BackendBridge | null = null;
const messageListeners = [];
const uri = 'ws://' + host + ':' + port;
diff --git a/packages/react-devtools-core/src/standalone.js b/packages/react-devtools-core/src/standalone.js
index 7bd636b80e448..b9fc4ff25a805 100644
--- a/packages/react-devtools-core/src/standalone.js
+++ b/packages/react-devtools-core/src/standalone.js
@@ -17,6 +17,7 @@ import DevTools from 'src/devtools/views/DevTools';
import launchEditor from './launchEditor';
import { __DEBUG__ } from 'src/constants';
+import type { FrontendBridge } from 'src/bridge';
import type { InspectedElement } from 'src/devtools/views/Components/types';
installHook(window);
@@ -46,7 +47,7 @@ function setStatusListener(value: StatusListener) {
return DevtoolsUI;
}
-let bridge: Bridge | null = null;
+let bridge: FrontendBridge | null = null;
let store: Store | null = null;
let root = null;
@@ -83,7 +84,7 @@ function reload() {
root = createRoot(node);
root.render(
createElement(DevTools, {
- bridge: ((bridge: any): Bridge),
+ bridge: ((bridge: any): FrontendBridge),
showTabBar: true,
store: ((store: any): Store),
warnIfLegacyBackendDetected: true,
@@ -166,7 +167,7 @@ function initialize(socket: WebSocket) {
}
},
});
- ((bridge: any): Bridge).addListener('shutdown', () => {
+ ((bridge: any): FrontendBridge).addListener('shutdown', () => {
socket.close();
});
diff --git a/shells/dev/app/SuspenseTree/index.js b/shells/dev/app/SuspenseTree/index.js
index e9a1fef4d2b5b..873f210e163d8 100644
--- a/shells/dev/app/SuspenseTree/index.js
+++ b/shells/dev/app/SuspenseTree/index.js
@@ -1,17 +1,17 @@
// @flow
-import React, { Suspense, useState } from 'react';
+import React, { Fragment, Suspense, useState } from 'react';
function SuspenseTree() {
return (
- <>
+
Suspense
Primary to Fallback Cycle
Fallback to Primary Cycle
- >
+
);
}
@@ -20,7 +20,7 @@ function PrimaryFallbackTest({ initialSuspend }) {
const fallbackStep = useTestSequence('fallback', Fallback1, Fallback2);
const primaryStep = useTestSequence('primary', Primary1, Primary2);
return (
- <>
+
);
}
@@ -45,32 +45,32 @@ function useTestSequence(label, T1, T2) {
);
let allSteps = [
- <>{next}>,
- <>
+ {next},
+
{next} mount
- >,
- <>
+ ,
+
{next} update
- >,
- <>
+ ,
+
{next} several different{' '}
children
- >,
- <>
+ ,
+
{next} goodbye
- >,
+ ,
];
return allSteps[step];
}
function NestedSuspenseTest() {
return (
- <>
+
Nested Suspense
Loading outer}>
- >
+
);
}
@@ -118,19 +118,19 @@ function Never() {
throw new Promise(resolve => {});
}
-function Fallback1({ prop, ...rest }) {
+function Fallback1({ prop, ...rest }: any) {
return ;
}
-function Fallback2({ prop, ...rest }) {
+function Fallback2({ prop, ...rest }: any) {
return ;
}
-function Primary1({ prop, ...rest }) {
+function Primary1({ prop, ...rest }: any) {
return ;
}
-function Primary2({ prop, ...rest }) {
+function Primary2({ prop, ...rest }: any) {
return ;
}
diff --git a/src/__tests__/bridge-test.js b/src/__tests__/bridge-test.js
index 1a9b4b949a5cf..fe89a6c2b10f9 100644
--- a/src/__tests__/bridge-test.js
+++ b/src/__tests__/bridge-test.js
@@ -15,9 +15,9 @@ describe('Bridge', () => {
const bridge = new Bridge(wall);
// Check that we're wired up correctly.
- bridge.send('init');
+ bridge.send('reloadAppForProfiling');
jest.runAllTimers();
- expect(wall.send).toHaveBeenCalledWith('init', undefined, undefined);
+ expect(wall.send).toHaveBeenCalledWith('reloadAppForProfiling');
// Should flush pending messages and then shut down.
wall.send.mockClear();
@@ -25,9 +25,9 @@ describe('Bridge', () => {
bridge.send('update', '2');
bridge.shutdown();
jest.runAllTimers();
- expect(wall.send).toHaveBeenCalledWith('update', '1', undefined);
- expect(wall.send).toHaveBeenCalledWith('update', '2', undefined);
- expect(wall.send).toHaveBeenCalledWith('shutdown', undefined, undefined);
+ expect(wall.send).toHaveBeenCalledWith('update', '1');
+ expect(wall.send).toHaveBeenCalledWith('update', '2');
+ expect(wall.send).toHaveBeenCalledWith('shutdown');
// Verify that the Bridge doesn't send messages after shutdown.
spyOn(console, 'warn');
diff --git a/src/__tests__/inspectedElementContext-test.js b/src/__tests__/inspectedElementContext-test.js
index 2fdbfe95e8904..2cf1ed8632975 100644
--- a/src/__tests__/inspectedElementContext-test.js
+++ b/src/__tests__/inspectedElementContext-test.js
@@ -2,14 +2,14 @@
import typeof ReactTestRenderer from 'react-test-renderer';
import type { GetInspectedElementPath } from 'src/devtools/views/Components/InspectedElementContext';
-import type Bridge from 'src/bridge';
+import type { FrontendBridge } from 'src/bridge';
import type Store from 'src/devtools/store';
describe('InspectedElementContext', () => {
let React;
let ReactDOM;
let TestRenderer: ReactTestRenderer;
- let bridge: Bridge;
+ let bridge: FrontendBridge;
let store: Store;
let meta;
let utils;
diff --git a/src/__tests__/legacy/inspectElement-test.js b/src/__tests__/legacy/inspectElement-test.js
index f71d22343f150..7b8c2b04a9f52 100644
--- a/src/__tests__/legacy/inspectElement-test.js
+++ b/src/__tests__/legacy/inspectElement-test.js
@@ -2,7 +2,7 @@
import type { InspectedElementPayload } from 'src/backend/types';
import type { DehydratedData } from 'src/devtools/views/Components/types';
-import type Bridge from 'src/bridge';
+import type { FrontendBridge } from 'src/bridge';
import type Store from 'src/devtools/store';
describe('InspectedElementContext', () => {
@@ -10,7 +10,7 @@ describe('InspectedElementContext', () => {
let ReactDOM;
let hydrate;
let meta;
- let bridge: Bridge;
+ let bridge: FrontendBridge;
let store: Store;
const act = (callback: Function) => {
diff --git a/src/__tests__/ownersListContext-test.js b/src/__tests__/ownersListContext-test.js
index 7dde191cf997a..97681b70bdde5 100644
--- a/src/__tests__/ownersListContext-test.js
+++ b/src/__tests__/ownersListContext-test.js
@@ -2,14 +2,14 @@
import typeof ReactTestRenderer from 'react-test-renderer';
import type { Element } from 'src/devtools/views/Components/types';
-import type Bridge from 'src/bridge';
+import type { FrontendBridge } from 'src/bridge';
import type Store from 'src/devtools/store';
describe('OwnersListContext', () => {
let React;
let ReactDOM;
let TestRenderer: ReactTestRenderer;
- let bridge: Bridge;
+ let bridge: FrontendBridge;
let store: Store;
let utils;
diff --git a/src/__tests__/profilerContext-test.js b/src/__tests__/profilerContext-test.js
index 6857ddb4070cf..c06f70d0390d2 100644
--- a/src/__tests__/profilerContext-test.js
+++ b/src/__tests__/profilerContext-test.js
@@ -1,7 +1,7 @@
// @flow
import typeof ReactTestRenderer from 'react-test-renderer';
-import type Bridge from 'src/bridge';
+import type { FrontendBridge } from 'src/bridge';
import type { Context } from 'src/devtools/views/Profiler/ProfilerContext';
import type { DispatcherContext } from 'src/devtools/views/Components/TreeContext';
import type Store from 'src/devtools/store';
@@ -10,7 +10,7 @@ describe('ProfilerContext', () => {
let React;
let ReactDOM;
let TestRenderer: ReactTestRenderer;
- let bridge: Bridge;
+ let bridge: FrontendBridge;
let store: Store;
let utils;
diff --git a/src/__tests__/profilingCache-test.js b/src/__tests__/profilingCache-test.js
index e5b56028936fd..6f6e4742cda4f 100644
--- a/src/__tests__/profilingCache-test.js
+++ b/src/__tests__/profilingCache-test.js
@@ -1,7 +1,7 @@
// @flow
import typeof ReactTestRenderer from 'react-test-renderer';
-import type Bridge from 'src/bridge';
+import type { FrontendBridge } from 'src/bridge';
import type Store from 'src/devtools/store';
describe('ProfilingCache', () => {
@@ -11,7 +11,7 @@ describe('ProfilingCache', () => {
let Scheduler;
let SchedulerTracing;
let TestRenderer: ReactTestRenderer;
- let bridge: Bridge;
+ let bridge: FrontendBridge;
let store: Store;
let utils;
diff --git a/src/__tests__/profilingCharts-test.js b/src/__tests__/profilingCharts-test.js
index dbf1ee16544b3..0e7fff951e940 100644
--- a/src/__tests__/profilingCharts-test.js
+++ b/src/__tests__/profilingCharts-test.js
@@ -29,7 +29,7 @@ describe('profiling charts', () => {
describe('flamegraph chart', () => {
it('should contain valid data', () => {
- const Parent = ({ count }) => {
+ const Parent = (_: {||}) => {
Scheduler.unstable_advanceTime(10);
return (
@@ -105,7 +105,7 @@ describe('profiling charts', () => {
describe('ranked chart', () => {
it('should contain valid data', () => {
- const Parent = ({ count }) => {
+ const Parent = (_: {||}) => {
Scheduler.unstable_advanceTime(10);
return (
@@ -177,7 +177,7 @@ describe('profiling charts', () => {
describe('interactions', () => {
it('should contain valid data', () => {
- const Parent = ({ count }) => {
+ const Parent = (_: {||}) => {
Scheduler.unstable_advanceTime(10);
return (
diff --git a/src/__tests__/setupTests.js b/src/__tests__/setupTests.js
index 18127c4d47ad7..3fb0a57a2f279 100644
--- a/src/__tests__/setupTests.js
+++ b/src/__tests__/setupTests.js
@@ -1,5 +1,7 @@
// @flow
+import type { BackendBridge, FrontendBridge } from 'src/bridge';
+
const env = jasmine.getEnv();
env.beforeEach(() => {
// These files should be required (and re-reuired) before each test,
@@ -51,13 +53,13 @@ env.beforeEach(() => {
},
});
- const agent = new Agent(bridge);
+ const agent = new Agent(((bridge: any): BackendBridge));
const hook = global.__REACT_DEVTOOLS_GLOBAL_HOOK__;
initBackend(hook, agent, global);
- const store = new Store(bridge);
+ const store = new Store(((bridge: any): FrontendBridge));
global.agent = agent;
global.bridge = bridge;
diff --git a/src/__tests__/storeComponentFilters-test.js b/src/__tests__/storeComponentFilters-test.js
index 3b7cfa53010d3..5e2385b33b96b 100644
--- a/src/__tests__/storeComponentFilters-test.js
+++ b/src/__tests__/storeComponentFilters-test.js
@@ -1,6 +1,6 @@
// @flow
-import type Bridge from 'src/bridge';
+import type { FrontendBridge } from 'src/bridge';
import type Store from 'src/devtools/store';
describe('Store component filters', () => {
@@ -8,7 +8,7 @@ describe('Store component filters', () => {
let ReactDOM;
let TestUtils;
let Types;
- let bridge: Bridge;
+ let bridge: FrontendBridge;
let store: Store;
let utils;
diff --git a/src/__tests__/treeContext-test.js b/src/__tests__/treeContext-test.js
index 09940efe95dd0..ecf8d47717436 100644
--- a/src/__tests__/treeContext-test.js
+++ b/src/__tests__/treeContext-test.js
@@ -1,7 +1,7 @@
// @flow
import typeof ReactTestRenderer from 'react-test-renderer';
-import type Bridge from 'src/bridge';
+import type { FrontendBridge } from 'src/bridge';
import type Store from 'src/devtools/store';
import type {
DispatcherContext,
@@ -12,7 +12,7 @@ describe('TreeListContext', () => {
let React;
let ReactDOM;
let TestRenderer: ReactTestRenderer;
- let bridge: Bridge;
+ let bridge: FrontendBridge;
let store: Store;
let utils;
diff --git a/src/__tests__/utils.js b/src/__tests__/utils.js
index 345b773832aaf..bf0c816109fa0 100644
--- a/src/__tests__/utils.js
+++ b/src/__tests__/utils.js
@@ -2,7 +2,7 @@
import typeof ReactTestRenderer from 'react-test-renderer';
-import type Bridge from 'src/bridge';
+import type { FrontendBridge } from 'src/bridge';
import type Store from 'src/devtools/store';
import type { ProfilingDataFrontend } from 'src/devtools/views/Profiler/types';
import type { ElementType } from 'src/types';
@@ -161,7 +161,7 @@ export function requireTestRenderer(): ReactTestRenderer {
}
}
-export function exportImportHelper(bridge: Bridge, store: Store): void {
+export function exportImportHelper(bridge: FrontendBridge, store: Store): void {
const { act } = require('./utils');
const {
prepareProfilingDataExport,
diff --git a/src/backend/NativeStyleEditor/setupNativeStyleEditor.js b/src/backend/NativeStyleEditor/setupNativeStyleEditor.js
index 5880bbac4d407..642dbb91eb87e 100644
--- a/src/backend/NativeStyleEditor/setupNativeStyleEditor.js
+++ b/src/backend/NativeStyleEditor/setupNativeStyleEditor.js
@@ -1,16 +1,16 @@
// @flow
import Agent from 'src/backend/agent';
-import Bridge from 'src/bridge';
import resolveBoxStyle from './resolveBoxStyle';
+import type { BackendBridge } from 'src/bridge';
import type { RendererID } from '../types';
import type { StyleAndLayout } from './types';
export type ResolveNativeStyle = (stylesheetID: number) => ?Object;
export default function setupNativeStyleEditor(
- bridge: Bridge,
+ bridge: BackendBridge,
agent: Agent,
resolveNativeStyle: ResolveNativeStyle,
validAttributes?: $ReadOnlyArray | null
@@ -81,7 +81,7 @@ const componentIDToStyleOverrides: Map = new Map();
function measureStyle(
agent: Agent,
- bridge: Bridge,
+ bridge: BackendBridge,
resolveNativeStyle: ResolveNativeStyle,
id: number,
rendererID: RendererID
diff --git a/src/backend/agent.js b/src/backend/agent.js
index fadd2e697ee55..9d8c4cff37103 100644
--- a/src/backend/agent.js
+++ b/src/backend/agent.js
@@ -2,7 +2,6 @@
import EventEmitter from 'events';
import throttle from 'lodash.throttle';
-import Bridge from 'src/bridge';
import {
SESSION_STORAGE_LAST_SELECTION_KEY,
SESSION_STORAGE_RELOAD_AND_PROFILE_KEY,
@@ -17,6 +16,7 @@ import {
import setupHighlighter from './views/Highlighter';
import { patch as patchConsole, unpatch as unpatchConsole } from './console';
+import type { BackendBridge } from 'src/bridge';
import type {
InstanceAndStyle,
NativeType,
@@ -81,14 +81,14 @@ export default class Agent extends EventEmitter<{|
showNativeHighlight: [NativeType],
shutdown: [],
|}> {
- _bridge: Bridge;
+ _bridge: BackendBridge;
_isProfiling: boolean = false;
_recordChangeDescriptions: boolean = false;
_rendererInterfaces: { [key: RendererID]: RendererInterface } = {};
_persistedSelection: PersistedSelection | null = null;
_persistedSelectionMatch: PathMatch | null = null;
- constructor(bridge: Bridge) {
+ constructor(bridge: BackendBridge) {
super();
if (
@@ -259,7 +259,7 @@ export default class Agent extends EventEmitter<{|
dataURL: string,
rootID: number,
|}) => {
- this._bridge.send('screenshotCaptured', { commitIndex, dataURL });
+ this._bridge.send('screenshotCaptured', { commitIndex, dataURL, rootID });
};
selectElement = ({ id, rendererID }: ElementAndRendererID) => {
diff --git a/src/backend/views/Highlighter/Overlay.js b/src/backend/views/Highlighter/Overlay.js
index 55ef361dc6278..f2190066b4791 100644
--- a/src/backend/views/Highlighter/Overlay.js
+++ b/src/backend/views/Highlighter/Overlay.js
@@ -11,6 +11,8 @@ type Rect = {
width: number,
};
+type Box = {| top: number, left: number, width: number, height: number |};
+
// Note that the Overlay components are not affected by the active Theme,
// because they highlight elements in the main Chrome window (outside of devtools).
// The colors below were chosen to roughly match those used by Chrome devtools.
@@ -21,7 +23,7 @@ class OverlayRect {
padding: HTMLElement;
content: HTMLElement;
- constructor(doc, container) {
+ constructor(doc: Document, container: HTMLElement) {
this.node = doc.createElement('div');
this.border = doc.createElement('div');
this.padding = doc.createElement('div');
@@ -51,7 +53,7 @@ class OverlayRect {
}
}
- update(box, dims) {
+ update(box: Rect, dims: any) {
boxWrap(dims, 'margin', this.node);
boxWrap(dims, 'border', this.border);
boxWrap(dims, 'padding', this.padding);
@@ -85,7 +87,7 @@ class OverlayTip {
nameSpan: HTMLElement;
dimSpan: HTMLElement;
- constructor(doc, container) {
+ constructor(doc: Document, container: HTMLElement) {
this.tip = doc.createElement('div');
assign(this.tip.style, {
display: 'flex',
@@ -126,13 +128,13 @@ class OverlayTip {
}
}
- updateText(name, width, height) {
+ updateText(name: string, width: number, height: number) {
this.nameSpan.textContent = name;
this.dimSpan.textContent =
Math.round(width) + 'px × ' + Math.round(height) + 'px';
}
- updatePosition(dims, bounds) {
+ updatePosition(dims: Box, bounds: Box) {
const tipRect = this.tip.getBoundingClientRect();
const tipPos = findTipPos(dims, bounds, {
width: tipRect.width,
@@ -247,6 +249,7 @@ export default class Overlay {
this.tipBoundsWindow.document.documentElement,
this.window
);
+
this.tip.updatePosition(
{
top: outerBox.top,
diff --git a/src/backend/views/Highlighter/index.js b/src/backend/views/Highlighter/index.js
index 3096b6fab3ebd..70d64e4cbc058 100644
--- a/src/backend/views/Highlighter/index.js
+++ b/src/backend/views/Highlighter/index.js
@@ -2,11 +2,15 @@
import memoize from 'memoize-one';
import throttle from 'lodash.throttle';
-import Bridge from 'src/bridge';
import Agent from 'src/backend/agent';
import { hideOverlay, showOverlay } from './Highlighter';
-export default function setup(bridge: Bridge, agent: Agent): void {
+import type { BackendBridge } from 'src/bridge';
+
+export default function setupHighlighter(
+ bridge: BackendBridge,
+ agent: Agent
+): void {
bridge.addListener(
'clearNativeElementHighlight',
clearNativeElementHighlight
@@ -50,7 +54,7 @@ export default function setup(bridge: Bridge, agent: Agent): void {
rendererID,
scrollIntoView,
}: {
- displayName: string,
+ displayName: string | null,
hideAfterTimeout: boolean,
id: number,
openNativeElementsPanel: boolean,
diff --git a/src/bridge.js b/src/bridge.js
index 23b887af7fc7e..b8ab73e710e9a 100644
--- a/src/bridge.js
+++ b/src/bridge.js
@@ -22,7 +22,7 @@ type Message = {|
type HighlightElementInDOM = {|
...ElementAndRendererID,
- displayName: string,
+ displayName: string | null,
hideAfterTimeout: boolean,
openNativeElementsPanel: boolean,
scrollIntoView: boolean,
@@ -62,33 +62,48 @@ type NativeStyleEditor_SetValueParams = {|
value: string,
|};
-export default class Bridge extends EventEmitter<{|
+type BackendEvents = {|
+ captureScreenshot: [{| commitIndex: number, rootID: number |}],
+ inspectedElement: [InspectedElementPayload],
+ isBackendStorageAPISupported: [boolean],
+ operations: [Array],
+ ownersList: [OwnersList],
+ overrideComponentFilters: [Array],
+ profilingData: [ProfilingDataBackend],
+ profilingStatus: [boolean],
+ reloadAppForProfiling: [],
+ screenshotCaptured: [
+ {| commitIndex: number, dataURL: string, rootID: number |},
+ ],
+ selectFiber: [number],
+ shutdown: [],
+ stopInspectingNative: [boolean],
+ syncSelectionFromNativeElementsPanel: [],
+ syncSelectionToNativeElementsPanel: [],
+
+ // React Native style editor plug-in.
+ isNativeStyleEditorSupported: [
+ {| isSupported: boolean, validAttributes: ?$ReadOnlyArray |},
+ ],
+ NativeStyleEditor_styleAndLayout: [StyleAndLayoutPayload],
+|};
+
+type FrontendEvents = {|
captureScreenshot: [{| commitIndex: number, rootID: number |}],
clearNativeElementHighlight: [],
getOwnersList: [ElementAndRendererID],
getProfilingData: [{| rendererID: RendererID |}],
getProfilingStatus: [],
highlightNativeElement: [HighlightElementInDOM],
- init: [],
inspectElement: [InspectElementParams],
- inspectedElement: [InspectedElementPayload],
- isBackendStorageAPISupported: [boolean],
logElementToConsole: [ElementAndRendererID],
- operations: [Array],
- ownersList: [OwnersList],
- overrideComponentFilters: [Array],
overrideContext: [OverrideValue],
overrideHookState: [OverrideHookState],
overrideProps: [OverrideValue],
overrideState: [OverrideValue],
overrideSuspense: [OverrideSuspense],
profilingData: [ProfilingDataBackend],
- profilingStatus: [boolean],
reloadAndProfile: [boolean],
- reloadAppForProfiling: [],
- screenshotCaptured: [
- {| commitIndex: number, dataURL: string, rootID: number |},
- ],
selectElement: [ElementAndRendererID],
selectFiber: [number],
shutdown: [],
@@ -96,20 +111,22 @@ export default class Bridge extends EventEmitter<{|
startProfiling: [boolean],
stopInspectingNative: [boolean],
stopProfiling: [],
- syncSelectionFromNativeElementsPanel: [],
- syncSelectionToNativeElementsPanel: [],
updateAppendComponentStack: [boolean],
updateComponentFilters: [Array],
viewElementSource: [ElementAndRendererID],
// React Native style editor plug-in.
- isNativeStyleEditorSupported: [
- {| isSupported: boolean, validAttributes: $ReadOnlyArray |},
- ],
NativeStyleEditor_measure: [ElementAndRendererID],
NativeStyleEditor_renameAttribute: [NativeStyleEditor_RenameAttributeParams],
NativeStyleEditor_setValue: [NativeStyleEditor_SetValueParams],
- NativeStyleEditor_styleAndLayout: [StyleAndLayoutPayload],
+|};
+
+class Bridge<
+ OutgoingEvents: Object,
+ IncomingEvents: Object
+> extends EventEmitter<{|
+ ...IncomingEvents,
+ ...OutgoingEvents,
|}> {
_isShutdown: boolean = false;
_messageQueue: Array = [];
@@ -134,7 +151,10 @@ export default class Bridge extends EventEmitter<{|
return this._wall;
}
- send(event: string, payload: any, transferable?: Array) {
+ send>(
+ event: EventName,
+ ...payload: $ElementType
+ ) {
if (this._isShutdown) {
console.warn(
`Cannot send message "${event}" through a Bridge that has been shutdown.`
@@ -150,7 +170,7 @@ export default class Bridge extends EventEmitter<{|
// - if there *has* been a message flushed in the last BATCH_DURATION ms
// (or we're waiting for our setTimeout-0 to fire), then _timeoutID will
// be set, and we'll simply add to the queue and wait for that
- this._messageQueue.push(event, payload, transferable);
+ this._messageQueue.push(event, payload);
if (!this._timeoutID) {
this._timeoutID = setTimeout(this._flush, 0);
}
@@ -204,12 +224,8 @@ export default class Bridge extends EventEmitter<{|
this._timeoutID = null;
if (this._messageQueue.length) {
- for (let i = 0; i < this._messageQueue.length; i += 3) {
- this._wall.send(
- this._messageQueue[i],
- this._messageQueue[i + 1],
- this._messageQueue[i + 2]
- );
+ for (let i = 0; i < this._messageQueue.length; i += 2) {
+ this._wall.send(this._messageQueue[i], ...this._messageQueue[i + 1]);
}
this._messageQueue.length = 0;
@@ -220,3 +236,8 @@ export default class Bridge extends EventEmitter<{|
}
};
}
+
+export type BackendBridge = Bridge;
+export type FrontendBridge = Bridge;
+
+export default Bridge;
diff --git a/src/devtools/ProfilerStore.js b/src/devtools/ProfilerStore.js
index bf2e8544a3f66..eb79c41e65b09 100644
--- a/src/devtools/ProfilerStore.js
+++ b/src/devtools/ProfilerStore.js
@@ -3,11 +3,11 @@
import EventEmitter from 'events';
import memoize from 'memoize-one';
import throttle from 'lodash.throttle';
-import Bridge from 'src/bridge';
import { prepareProfilingDataFrontendFromBackendAndStore } from './views/Profiler/utils';
import ProfilingCache from './ProfilingCache';
import Store from './store';
+import type { FrontendBridge } from 'src/bridge';
import type { ProfilingDataBackend } from 'src/backend/types';
import type {
CommitDataFrontend,
@@ -23,7 +23,7 @@ export default class ProfilerStore extends EventEmitter<{|
isProfiling: [],
profilingData: [],
|}> {
- _bridge: Bridge;
+ _bridge: FrontendBridge;
// Suspense cache for lazily calculating derived profiling data.
_cache: ProfilingCache;
@@ -79,7 +79,11 @@ export default class ProfilerStore extends EventEmitter<{|
_store: Store;
- constructor(bridge: Bridge, store: Store, defaultIsProfiling: boolean) {
+ constructor(
+ bridge: FrontendBridge,
+ store: Store,
+ defaultIsProfiling: boolean
+ ) {
super();
this._bridge = bridge;
diff --git a/src/devtools/index.js b/src/devtools/index.js
index b41b51a1102dd..33e628e96542a 100644
--- a/src/devtools/index.js
+++ b/src/devtools/index.js
@@ -1,6 +1,6 @@
// @flow
-import Bridge from 'src/bridge';
+import type { FrontendBridge } from 'src/bridge';
type Shell = {|
connect: (callback: Function) => void,
@@ -8,7 +8,7 @@ type Shell = {|
|};
export function initDevTools(shell: Shell) {
- shell.connect((bridge: Bridge) => {
+ shell.connect((bridge: FrontendBridge) => {
// TODO ...
});
}
diff --git a/src/devtools/store.js b/src/devtools/store.js
index 2c778a0ccd002..5b3e6a34d75f7 100644
--- a/src/devtools/store.js
+++ b/src/devtools/store.js
@@ -2,7 +2,6 @@
import EventEmitter from 'events';
import { inspect } from 'util';
-import Bridge from 'src/bridge';
import {
TREE_OPERATION_ADD,
TREE_OPERATION_REMOVE,
@@ -24,6 +23,7 @@ import ProfilerStore from './ProfilerStore';
import type { Element } from './views/Components/types';
import type { ComponentFilter, ElementType } from '../types';
+import type { FrontendBridge } from 'src/bridge';
const debug = (methodName, ...args) => {
if (__DEBUG__) {
@@ -71,7 +71,7 @@ export default class Store extends EventEmitter<{|
supportsProfiling: [],
supportsReloadAndProfile: [],
|}> {
- _bridge: Bridge;
+ _bridge: FrontendBridge;
_captureScreenshots: boolean = false;
@@ -129,7 +129,7 @@ export default class Store extends EventEmitter<{|
// Used for windowing purposes.
_weightAcrossRoots: number = 0;
- constructor(bridge: Bridge, config?: Config) {
+ constructor(bridge: FrontendBridge, config?: Config) {
super();
if (__DEBUG__) {
@@ -701,7 +701,7 @@ export default class Store extends EventEmitter<{|
validAttributes,
}: {|
isSupported: boolean,
- validAttributes: $ReadOnlyArray,
+ validAttributes: ?$ReadOnlyArray,
|}) => {
this._isNativeStyleEditorSupported = isSupported;
this._nativeStyleEditorValidAttributes = validAttributes || null;
diff --git a/src/devtools/views/Components/HooksTree.js b/src/devtools/views/Components/HooksTree.js
index 0c3b3e79b2a57..10df0c470a65e 100644
--- a/src/devtools/views/Components/HooksTree.js
+++ b/src/devtools/views/Components/HooksTree.js
@@ -221,17 +221,19 @@ function HookView({
if (canEditHooks && isStateEditable) {
overrideValueFn = (absolutePath: Array, value: any) => {
const rendererID = store.getRendererIDForElement(id);
- bridge.send('overrideHookState', {
- id,
- hookID,
- // Hooks override function expects a relative path for the specified hook (id),
- // starting with its id within the (flat) hooks list structure.
- // This relative path does not include the fake tree structure DevTools uses for display,
- // so it's important that we remove that part of the path before sending the update.
- path: absolutePath.slice(path.length + 1),
- rendererID,
- value,
- });
+ if (rendererID !== null) {
+ bridge.send('overrideHookState', {
+ id,
+ hookID,
+ // Hooks override function expects a relative path for the specified hook (id),
+ // starting with its id within the (flat) hooks list structure.
+ // This relative path does not include the fake tree structure DevTools uses for display,
+ // so it's important that we remove that part of the path before sending the update.
+ path: absolutePath.slice(path.length + 1),
+ rendererID,
+ value,
+ });
+ }
};
}
diff --git a/src/devtools/views/Components/InspectedElementContext.js b/src/devtools/views/Components/InspectedElementContext.js
index 97efcac574ff2..31841774eb631 100644
--- a/src/devtools/views/Components/InspectedElementContext.js
+++ b/src/devtools/views/Components/InspectedElementContext.js
@@ -85,7 +85,9 @@ function InspectedElementContextController({ children }: Props) {
const getInspectedElementPath = useCallback(
(id: number, path: Array) => {
const rendererID = store.getRendererIDForElement(id);
- bridge.send('inspectElement', { id, path, rendererID });
+ if (rendererID !== null) {
+ bridge.send('inspectElement', { id, path, rendererID });
+ }
},
[bridge, store]
);
@@ -232,7 +234,9 @@ function InspectedElementContextController({ children }: Props) {
const sendRequest = () => {
timeoutID = null;
- bridge.send('inspectElement', { id: selectedElementID, rendererID });
+ if (rendererID !== null) {
+ bridge.send('inspectElement', { id: selectedElementID, rendererID });
+ }
};
// Send the initial inspection request.
@@ -240,7 +244,9 @@ function InspectedElementContextController({ children }: Props) {
sendRequest();
// Update the $r variable.
- bridge.send('selectElement', { id: selectedElementID, rendererID });
+ if (rendererID !== null) {
+ bridge.send('selectElement', { id: selectedElementID, rendererID });
+ }
const onInspectedElement = (data: InspectedElementPayload) => {
// If this is the element we requested, wait a little bit and then ask for another update.
diff --git a/src/devtools/views/Components/NativeStyleEditor/StyleEditor.js b/src/devtools/views/Components/NativeStyleEditor/StyleEditor.js
index 570f473355eea..94d6923c37f1d 100644
--- a/src/devtools/views/Components/NativeStyleEditor/StyleEditor.js
+++ b/src/devtools/views/Components/NativeStyleEditor/StyleEditor.js
@@ -25,22 +25,28 @@ export default function StyleEditor({ id, style }: Props) {
const store = useContext(StoreContext);
const changeAttribute = (oldName: string, newName: string, value: any) => {
- bridge.send('NativeStyleEditor_renameAttribute', {
- id,
- rendererID: store.getRendererIDForElement(id),
- oldName,
- newName,
- value,
- });
+ const rendererID = store.getRendererIDForElement(id);
+ if (rendererID !== null) {
+ bridge.send('NativeStyleEditor_renameAttribute', {
+ id,
+ rendererID,
+ oldName,
+ newName,
+ value,
+ });
+ }
};
const changeValue = (name: string, value: any) => {
- bridge.send('NativeStyleEditor_setValue', {
- id,
- rendererID: store.getRendererIDForElement(id),
- name,
- value,
- });
+ const rendererID = store.getRendererIDForElement(id);
+ if (rendererID !== null) {
+ bridge.send('NativeStyleEditor_setValue', {
+ id,
+ rendererID,
+ name,
+ value,
+ });
+ }
};
const keys = useMemo(() => Array.from(Object.keys(style)), [style]);
diff --git a/src/devtools/views/Components/NativeStyleEditor/context.js b/src/devtools/views/Components/NativeStyleEditor/context.js
index 927a4d4151d58..f062fef43e57a 100644
--- a/src/devtools/views/Components/NativeStyleEditor/context.js
+++ b/src/devtools/views/Components/NativeStyleEditor/context.js
@@ -136,10 +136,12 @@ function NativeStyleContextController({ children }: Props) {
const sendRequest = () => {
timeoutID = null;
- bridge.send('NativeStyleEditor_measure', {
- id: selectedElementID,
- rendererID,
- });
+ if (rendererID !== null) {
+ bridge.send('NativeStyleEditor_measure', {
+ id: selectedElementID,
+ rendererID,
+ });
+ }
};
// Send the initial measurement request.
diff --git a/src/devtools/views/Components/OwnersListContext.js b/src/devtools/views/Components/OwnersListContext.js
index aa7e2dab0503f..6da02d3546ed8 100644
--- a/src/devtools/views/Components/OwnersListContext.js
+++ b/src/devtools/views/Components/OwnersListContext.js
@@ -106,8 +106,9 @@ function OwnersListContextController({ children }: Props) {
useEffect(() => {
if (ownerID !== null) {
const rendererID = store.getRendererIDForElement(ownerID);
-
- bridge.send('getOwnersList', { id: ownerID, rendererID });
+ if (rendererID !== null) {
+ bridge.send('getOwnersList', { id: ownerID, rendererID });
+ }
}
return () => {};
diff --git a/src/devtools/views/Components/SelectedElement.js b/src/devtools/views/Components/SelectedElement.js
index 2d3eece429544..ecc12028c94e2 100644
--- a/src/devtools/views/Components/SelectedElement.js
+++ b/src/devtools/views/Components/SelectedElement.js
@@ -140,12 +140,18 @@ export default function SelectedElement(_: Props) {
});
}
+ const rendererID = store.getRendererIDForElement(
+ nearestSuspenseElementID
+ );
+
// Toggle suspended
- bridge.send('overrideSuspense', {
- id: nearestSuspenseElementID,
- rendererID: store.getRendererIDForElement(nearestSuspenseElementID),
- forceFallback: !isSuspended,
- });
+ if (rendererID !== null) {
+ bridge.send('overrideSuspense', {
+ id: nearestSuspenseElementID,
+ rendererID,
+ forceFallback: !isSuspended,
+ });
+ }
}
}, [bridge, dispatch, element, isSuspended, modalDialogDispatch, store]);
@@ -280,15 +286,21 @@ function InspectedElementView({
if (type === ElementTypeClass) {
overrideContextFn = (path: Array, value: any) => {
const rendererID = store.getRendererIDForElement(id);
- bridge.send('overrideContext', { id, path, rendererID, value });
+ if (rendererID !== null) {
+ bridge.send('overrideContext', { id, path, rendererID, value });
+ }
};
overridePropsFn = (path: Array, value: any) => {
const rendererID = store.getRendererIDForElement(id);
- bridge.send('overrideProps', { id, path, rendererID, value });
+ if (rendererID !== null) {
+ bridge.send('overrideProps', { id, path, rendererID, value });
+ }
};
overrideStateFn = (path: Array, value: any) => {
const rendererID = store.getRendererIDForElement(id);
- bridge.send('overrideState', { id, path, rendererID, value });
+ if (rendererID !== null) {
+ bridge.send('overrideState', { id, path, rendererID, value });
+ }
};
} else if (
(type === ElementTypeFunction ||
@@ -298,7 +310,9 @@ function InspectedElementView({
) {
overridePropsFn = (path: Array, value: any) => {
const rendererID = store.getRendererIDForElement(id);
- bridge.send('overrideProps', { id, path, rendererID, value });
+ if (rendererID !== null) {
+ bridge.send('overrideProps', { id, path, rendererID, value });
+ }
};
} else if (type === ElementTypeSuspense && canToggleSuspense) {
overrideSuspenseFn = (path: Array, value: boolean) => {
@@ -306,7 +320,13 @@ function InspectedElementView({
throw new Error('Unexpected path.');
}
const rendererID = store.getRendererIDForElement(id);
- bridge.send('overrideSuspense', { id, rendererID, forceFallback: value });
+ if (rendererID !== null) {
+ bridge.send('overrideSuspense', {
+ id,
+ rendererID,
+ forceFallback: value,
+ });
+ }
};
}
diff --git a/src/devtools/views/Components/Tree.js b/src/devtools/views/Components/Tree.js
index 85d3ef1658197..285cb39c41655 100644
--- a/src/devtools/views/Components/Tree.js
+++ b/src/devtools/views/Components/Tree.js
@@ -192,7 +192,7 @@ export default function Tree(props: Props) {
(id: number) => {
const element = store.getElementByID(id);
const rendererID = store.getRendererIDForElement(id);
- if (element !== null) {
+ if (element !== null && rendererID !== null) {
bridge.send('highlightNativeElement', {
displayName: element.displayName,
hideAfterTimeout: false,
diff --git a/src/devtools/views/DevTools.js b/src/devtools/views/DevTools.js
index f8d9bcec9186b..1aab4afaef5b8 100644
--- a/src/devtools/views/DevTools.js
+++ b/src/devtools/views/DevTools.js
@@ -6,7 +6,6 @@ import '@reach/menu-button/styles.css';
import '@reach/tooltip/styles.css';
import React, { useMemo, useState } from 'react';
-import Bridge from 'src/bridge';
import Store from '../store';
import { BridgeContext, StoreContext } from './context';
import Components from './Components/Components';
@@ -25,6 +24,7 @@ import styles from './DevTools.css';
import './root.css';
import type { InspectedElement } from 'src/devtools/views/Components/types';
+import type { FrontendBridge } from 'src/bridge';
export type BrowserTheme = 'dark' | 'light';
export type TabID = 'components' | 'profiler' | 'settings';
@@ -34,7 +34,7 @@ export type ViewElementSource = (
) => void;
export type Props = {|
- bridge: Bridge,
+ bridge: FrontendBridge,
browserTheme?: BrowserTheme,
defaultTab?: TabID,
showTabBar?: boolean,
diff --git a/src/devtools/views/context.js b/src/devtools/views/context.js
index e5ede9ef48a04..96c654a94397f 100644
--- a/src/devtools/views/context.js
+++ b/src/devtools/views/context.js
@@ -1,11 +1,13 @@
// @flow
import { createContext } from 'react';
-import Bridge from 'src/bridge';
-
import Store from '../store';
-export const BridgeContext = createContext(((null: any): Bridge));
+import type { FrontendBridge } from 'src/bridge';
+
+export const BridgeContext = createContext(
+ ((null: any): FrontendBridge)
+);
BridgeContext.displayName = 'BridgeContext';
export const StoreContext = createContext(((null: any): Store));
diff --git a/vendor/react-window/dist/index-dev.umd.js b/vendor/react-window/dist/index-dev.umd.js
new file mode 100644
index 0000000000000..96dc2ae17a611
--- /dev/null
+++ b/vendor/react-window/dist/index-dev.umd.js
@@ -0,0 +1,2 @@
+!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("react")):"function"==typeof define&&define.amd?define(["exports","react"],t):t((e=e||self).ReactWindow={},e.React)}(this,function(e,t){"use strict";function r(){return(r=Object.assign||function(e){for(var t=1;t=t?e.call(null):n.id=requestAnimationFrame(o)})};return n}var u=-1;var d=null;function f(e){if(void 0===e&&(e=!1),null===d||e){var t=document.createElement("div"),r=t.style;r.width="50px",r.height="50px",r.overflow="scroll",r.direction="rtl";var n=document.createElement("div"),o=n.style;return o.width="100px",o.height="100px",t.appendChild(n),document.body.appendChild(t),t.scrollLeft>0?d="positive-descending":(t.scrollLeft=1,d=0===t.scrollLeft?"negative":"positive-ascending"),document.body.removeChild(t),d}return d}var h=150,p=function(e){var t=e.columnIndex;e.data;return e.rowIndex+":"+t},m=null,v=null,g=null;function w(e){var i,l,d=e.getColumnOffset,m=e.getColumnStartIndexForOffset,v=e.getColumnStopIndexForStartIndex,g=e.getColumnWidth,w=e.getEstimatedTotalHeight,I=e.getEstimatedTotalWidth,M=e.getOffsetForColumnAndAlignment,y=e.getOffsetForRowAndAlignment,x=e.getRowHeight,C=e.getRowOffset,_=e.getRowStartIndexForOffset,b=e.getRowStopIndexForStartIndex,R=e.initInstanceProps,T=e.shouldResetStyleCacheOnItemSizeChange,z=e.validateProps;return l=i=function(e){function i(t){var r;return(r=e.call(this,t)||this)._instanceProps=R(r.props,o(o(r))),r._resetIsScrollingTimeoutId=null,r._outerRef=void 0,r.state={instance:o(o(r)),isScrolling:!1,horizontalScrollDirection:"forward",scrollLeft:"number"==typeof r.props.initialScrollLeft?r.props.initialScrollLeft:0,scrollTop:"number"==typeof r.props.initialScrollTop?r.props.initialScrollTop:0,scrollUpdateWasRequested:!1,verticalScrollDirection:"forward"},r._callOnItemsRendered=void 0,r._callOnItemsRendered=a(function(e,t,n,o,i,a,l,s){return r.props.onItemsRendered({overscanColumnStartIndex:e,overscanColumnStopIndex:t,overscanRowStartIndex:n,overscanRowStopIndex:o,visibleColumnStartIndex:i,visibleColumnStopIndex:a,visibleRowStartIndex:l,visibleRowStopIndex:s})}),r._callOnScroll=void 0,r._callOnScroll=a(function(e,t,n,o,i){return r.props.onScroll({horizontalScrollDirection:n,scrollLeft:e,scrollTop:t,verticalScrollDirection:o,scrollUpdateWasRequested:i})}),r._getItemStyle=void 0,r._getItemStyle=function(e,t){var n,o,i=r.props,a=i.columnWidth,l=i.direction,s=i.rowHeight,c=r._getItemStyleCache(T&&a,T&&l,T&&s),u=e+":"+t;c.hasOwnProperty(u)?n=c[u]:c[u]=((o={position:"absolute"})["rtl"===l?"right":"left"]=d(r.props,t,r._instanceProps),o.top=C(r.props,e,r._instanceProps),o.height=x(r.props,e,r._instanceProps),o.width=g(r.props,t,r._instanceProps),n=o);return n},r._getItemStyleCache=void 0,r._getItemStyleCache=a(function(e,t,r){return{}}),r._onScroll=function(e){var t=e.currentTarget,n=t.clientHeight,o=t.clientWidth,i=t.scrollLeft,a=t.scrollTop,l=t.scrollHeight,s=t.scrollWidth;r.setState(function(e){if(e.scrollLeft===i&&e.scrollTop===a)return null;var t=r.props.direction,c=i;if("rtl"===t)switch(f()){case"negative":c=-i;break;case"positive-descending":c=s-o-i}c=Math.max(0,Math.min(c,s-o));var u=Math.max(0,Math.min(a,l-n));return{isScrolling:!0,horizontalScrollDirection:e.scrollLeftc?p:0,g=m>l?p:0;this.scrollTo({scrollLeft:void 0!==n?M(this.props,n,r,f,this._instanceProps,g):f,scrollTop:void 0!==o?y(this.props,o,r,h,this._instanceProps,v):h})},l.componentDidMount=function(){var e=this.props,t=e.initialScrollLeft,r=e.initialScrollTop;if(null!=this._outerRef){var n=this._outerRef;"number"==typeof t&&(n.scrollLeft=t),"number"==typeof r&&(n.scrollTop=r)}this._callPropsCallbacks()},l.componentDidUpdate=function(){var e=this.props.direction,t=this.state,r=t.scrollLeft,n=t.scrollTop;if(t.scrollUpdateWasRequested&&null!=this._outerRef){var o=this._outerRef;if("rtl"===e)switch(f()){case"negative":o.scrollLeft=-r;break;case"positive-ascending":o.scrollLeft=r;break;default:var i=o.clientWidth,a=o.scrollWidth;o.scrollLeft=a-i-r}else o.scrollLeft=Math.max(0,r);o.scrollTop=Math.max(0,n)}this._callPropsCallbacks()},l.componentWillUnmount=function(){null!==this._resetIsScrollingTimeoutId&&s(this._resetIsScrollingTimeoutId)},l.render=function(){var e=this.props,n=e.children,o=e.className,i=e.columnCount,a=e.direction,l=e.height,s=e.innerRef,c=e.innerElementType,u=e.innerTagName,d=e.itemData,f=e.itemKey,h=void 0===f?p:f,m=e.outerElementType,v=e.outerTagName,g=e.rowCount,S=e.style,M=e.useIsScrolling,y=e.width,x=this.state.isScrolling,C=this._getHorizontalRangeToRender(),_=C[0],b=C[1],R=this._getVerticalRangeToRender(),T=R[0],z=R[1],O=[];if(i>0&&g)for(var P=T;P<=z;P++)for(var W=_;W<=b;W++)O.push(t.createElement(n,{columnIndex:W,data:d,isScrolling:M?x:void 0,key:h({columnIndex:W,data:d,rowIndex:P}),rowIndex:P,style:this._getItemStyle(P,W)}));var E=w(this.props,this._instanceProps),A=I(this.props,this._instanceProps);return t.createElement(m||v||"div",{className:o,onScroll:this._onScroll,ref:this._outerRefSetter,style:r({position:"relative",height:l,width:y,overflow:"auto",WebkitOverflowScrolling:"touch",willChange:"transform",direction:a},S)},t.createElement(c||u||"div",{children:O,ref:s,style:{height:E,pointerEvents:x?"none":void 0,width:A}}))},l._callPropsCallbacks=function(){var e=this.props,t=e.columnCount,r=e.onItemsRendered,n=e.onScroll,o=e.rowCount;if("function"==typeof r&&t>0&&o>0){var i=this._getHorizontalRangeToRender(),a=i[0],l=i[1],s=i[2],c=i[3],u=this._getVerticalRangeToRender(),d=u[0],f=u[1],h=u[2],p=u[3];this._callOnItemsRendered(a,l,d,f,s,c,h,p)}if("function"==typeof n){var m=this.state,v=m.horizontalScrollDirection,g=m.scrollLeft,w=m.scrollTop,S=m.scrollUpdateWasRequested,I=m.verticalScrollDirection;this._callOnScroll(g,w,v,I,S)}},l._getHorizontalRangeToRender=function(){var e=this.props,t=e.columnCount,r=e.overscanColumnCount,n=e.overscanColumnsCount,o=e.overscanCount,i=e.rowCount,a=this.state,l=a.horizontalScrollDirection,s=a.isScrolling,c=a.scrollLeft,u=r||n||o||1;if(0===t||0===i)return[0,0,0,0];var d=m(this.props,c,this._instanceProps),f=v(this.props,d,c,this._instanceProps),h=s&&"backward"!==l?1:Math.max(1,u),p=s&&"forward"!==l?1:Math.max(1,u);return[Math.max(0,d-h),Math.max(0,Math.min(t-1,f+p)),d,f]},l._getVerticalRangeToRender=function(){var e=this.props,t=e.columnCount,r=e.overscanCount,n=e.overscanRowCount,o=e.overscanRowsCount,i=e.rowCount,a=this.state,l=a.isScrolling,s=a.verticalScrollDirection,c=a.scrollTop,u=n||o||r||1;if(0===t||0===i)return[0,0,0,0];var d=_(this.props,c,this._instanceProps),f=b(this.props,d,c,this._instanceProps),h=l&&"backward"!==s?1:Math.max(1,u),p=l&&"forward"!==s?1:Math.max(1,u);return[Math.max(0,d-h),Math.max(0,Math.min(i-1,f+p)),d,f]},i}(t.PureComponent),i.defaultProps={direction:"ltr",itemData:void 0,useIsScrolling:!1},l}"undefined"!=typeof window&&void 0!==window.WeakSet&&(m=new WeakSet,v=new WeakSet,g=new WeakSet);var S=function(e,t){var r=e.children,n=e.direction,o=e.height,i=e.innerTagName,a=e.outerTagName,l=e.overscanColumnsCount,s=e.overscanCount,c=e.overscanRowsCount,u=e.width,d=t.instance;if("number"==typeof s&&m&&!m.has(d)&&(m.add(d),console.warn("The overscanCount prop has been deprecated. Please use the overscanColumnCount and overscanRowCount props instead.")),"number"!=typeof l&&"number"!=typeof c||v&&!v.has(d)&&(v.add(d),console.warn("The overscanColumnsCount and overscanRowsCount props have been deprecated. Please use the overscanColumnCount and overscanRowCount props instead.")),null==i&&null==a||g&&!g.has(d)&&(g.add(d),console.warn("The innerTagName and outerTagName props have been deprecated. Please use the innerElementType and outerElementType props instead.")),null==r)throw Error('An invalid "children" prop has been specified. Value should be a React component. "'+(null===r?"null":typeof r)+'" was specified.');switch(n){case"ltr":case"rtl":break;default:throw Error('An invalid "direction" prop has been specified. Value should be either "ltr" or "rtl". "'+n+'" was specified.')}if("number"!=typeof u)throw Error('An invalid "width" prop has been specified. Grids must specify a number for width. "'+(null===u?"null":typeof u)+'" was specified.');if("number"!=typeof o)throw Error('An invalid "height" prop has been specified. Grids must specify a number for height. "'+(null===o?"null":typeof o)+'" was specified.')},I=function(e,t){var r=e.rowCount,n=t.rowMetadataMap,o=t.estimatedRowHeight,i=t.lastMeasuredRowIndex,a=0;if(i>=r&&(i=r-1),i>=0){var l=n[i];a=l.offset+l.size}return a+(r-i-1)*o},M=function(e,t){var r=e.columnCount,n=t.columnMetadataMap,o=t.estimatedColumnWidth,i=t.lastMeasuredColumnIndex,a=0;if(i>=r&&(i=r-1),i>=0){var l=n[i];a=l.offset+l.size}return a+(r-i-1)*o},y=function(e,t,r,n){var o,i,a;if("column"===e?(o=n.columnMetadataMap,i=t.columnWidth,a=n.lastMeasuredColumnIndex):(o=n.rowMetadataMap,i=t.rowHeight,a=n.lastMeasuredRowIndex),r>a){var l=0;if(a>=0){var s=o[a];l=s.offset+s.size}for(var c=a+1;c<=r;c++){var u=i(c);o[c]={offset:l,size:u},l+=u}"column"===e?n.lastMeasuredColumnIndex=r:n.lastMeasuredRowIndex=r}return o[r]},x=function(e,t,r,n){var o,i;return"column"===e?(o=r.columnMetadataMap,i=r.lastMeasuredColumnIndex):(o=r.rowMetadataMap,i=r.lastMeasuredRowIndex),(i>0?o[i].offset:0)>=n?C(e,t,r,i,0,n):_(e,t,r,Math.max(0,i),n)},C=function(e,t,r,n,o,i){for(;o<=n;){var a=o+Math.floor((n-o)/2),l=y(e,t,a,r).offset;if(l===i)return a;li&&(n=a-1)}return o>0?o-1:0},_=function(e,t,r,n,o){for(var i="column"===e?t.columnCount:t.rowCount,a=1;n=d-l&&o<=u+l?"auto":"center"),n){case"start":return u;case"end":return d;case"center":return Math.round(d+(u-d)/2);case"auto":default:return o>=d&&o<=u?o:d>u?d:o0)for(var T=_;T<=b;T++)R.push(t.createElement(n,{data:f,key:p(T,f),index:T,isScrolling:S?M:void 0,style:this._getItemStyle(T)}));var O=d(this.props,this._instanceProps);return t.createElement(v||g||"div",{className:o,onScroll:x,ref:this._outerRefSetter,style:r({position:"relative",height:a,width:I,overflow:"auto",WebkitOverflowScrolling:"touch",willChange:"transform",direction:i},w)},t.createElement(s||c||"div",{children:R,ref:l,style:{height:y?"100%":O,pointerEvents:M?"none":void 0,width:y?O:"100%"}}))},l._callPropsCallbacks=function(){if("function"==typeof this.props.onItemsRendered&&this.props.itemCount>0){var e=this._getRangeToRender(),t=e[0],r=e[1],n=e[2],o=e[3];this._callOnItemsRendered(t,r,n,o)}if("function"==typeof this.props.onScroll){var i=this.state,a=i.scrollDirection,l=i.scrollOffset,s=i.scrollUpdateWasRequested;this._callOnScroll(a,l,s)}},l._getRangeToRender=function(){var e=this.props,t=e.itemCount,r=e.overscanCount,n=this.state,o=n.isScrolling,i=n.scrollDirection,a=n.scrollOffset;if(0===t)return[0,0,0,0];var l=m(this.props,a,this._instanceProps),s=v(this.props,l,a,this._instanceProps),c=o&&"backward"!==i?1:Math.max(1,r),u=o&&"forward"!==i?1:Math.max(1,r);return[Math.max(0,l-c),Math.max(0,Math.min(t-1,s+u)),l,s]},i}(t.PureComponent),i.defaultProps={direction:"ltr",itemData:void 0,layout:"vertical",overscanCount:2,useIsScrolling:!1},l}"undefined"!=typeof window&&void 0!==window.WeakSet&&(O=new WeakSet,P=new WeakSet);var E=function(e,t){var r=e.children,n=e.direction,o=e.height,i=e.layout,a=e.innerTagName,l=e.outerTagName,s=e.width,c=t.instance;null==a&&null==l||P&&!P.has(c)&&(P.add(c),console.warn("The innerTagName and outerTagName props have been deprecated. Please use the innerElementType and outerElementType props instead."));var u="horizontal"===n||"horizontal"===i;switch(n){case"horizontal":case"vertical":O&&!O.has(c)&&(O.add(c),console.warn('The direction prop should be either "ltr" (default) or "rtl". Please use the layout prop to specify "vertical" (default) or "horizontal" orientation.'));break;case"ltr":case"rtl":break;default:throw Error('An invalid "direction" prop has been specified. Value should be either "ltr" or "rtl". "'+n+'" was specified.')}switch(i){case"horizontal":case"vertical":break;default:throw Error('An invalid "layout" prop has been specified. Value should be either "horizontal" or "vertical". "'+i+'" was specified.')}if(null==r)throw Error('An invalid "children" prop has been specified. Value should be a React component. "'+(null===r?"null":typeof r)+'" was specified.');if(u&&"number"!=typeof s)throw Error('An invalid "width" prop has been specified. Horizontal lists must specify a number for width. "'+(null===s?"null":typeof s)+'" was specified.');if(!u&&"number"!=typeof o)throw Error('An invalid "height" prop has been specified. Vertical lists must specify a number for height. "'+(null===o?"null":typeof o)+'" was specified.')},A=function(e,t,r){var n=e.itemSize,o=r.itemMetadataMap,i=r.lastMeasuredIndex;if(t>i){var a=0;if(i>=0){var l=o[i];a=l.offset+l.size}for(var s=i+1;s<=t;s++){var c=n(s);o[s]={offset:a,size:c},a+=c}r.lastMeasuredIndex=t}return o[t]},k=function(e,t,r,n,o){for(;n<=r;){var i=n+Math.floor((r-n)/2),a=A(e,i,t).offset;if(a===o)return i;ao&&(r=i-1)}return n>0?n-1:0},D=function(e,t,r,n){for(var o=e.itemCount,i=1;r=r&&(i=r-1),i>=0){var l=n[i];a=l.offset+l.size}return a+(r-i-1)*o},L=W({getItemOffset:function(e,t,r){return A(e,t,r).offset},getItemSize:function(e,t,r){return r.itemMetadataMap[t].size},getEstimatedTotalSize:F,getOffsetForIndexAndAlignment:function(e,t,r,n,o){var i=e.direction,a=e.height,l=e.layout,s=e.width,c="horizontal"===i||"horizontal"===l?s:a,u=A(e,t,o),d=F(e,o),f=Math.max(0,Math.min(d-c,u.offset)),h=Math.max(0,u.offset-c+u.size);switch("smart"===r&&(r=n>=h-c&&n<=f+c?"auto":"center"),r){case"start":return f;case"end":return h;case"center":return Math.round(h+(f-h)/2);case"auto":default:return n>=h&&n<=f?n:n0?n[o].offset:0)>=r?k(e,t,o,0,r):D(e,t,Math.max(0,o),r)}(e,r,t)},getStopIndexForStartIndex:function(e,t,r,n){for(var o=e.direction,i=e.height,a=e.itemCount,l=e.layout,s=e.width,c="horizontal"===o||"horizontal"===l?s:i,u=A(e,t,n),d=r+c,f=u.offset+u.size,h=t;h=d-s&&n<=u+s?"auto":"center"),r){case"start":return u;case"end":return d;case"center":var f=Math.round(d+(u-d)/2);return fc+Math.floor(s/2)?c:f;case"auto":default:return n>=d&&n<=u?n:d>u?d:n=d-l&&n<=u+l?"auto":"center"),r){case"start":return u;case"end":return d;case"center":var f=Math.round(d+(u-d)/2);return fc+Math.floor(l/2)?c:f;case"auto":default:return n>=d&&n<=u?n:d>u?d:n=h-u&&n<=f+u?"auto":"center"),r){case"start":return f;case"end":return h;case"center":var p=Math.round(h+(f-h)/2);return pd+Math.floor(u/2)?d:p;case"auto":default:return n>=h&&n<=f?n:n=0||(o[r]=e[r]);return o}function q(e,t){for(var r in e)if(!(r in t))return!0;for(var n in t)if(e[n]!==t[n])return!0;return!1}function N(e,t){var r=e.style,n=V(e,["style"]),o=t.style,i=V(t,["style"]);return!q(r,o)&&!q(n,i)}e.VariableSizeGrid=R,e.VariableSizeList=L,e.FixedSizeGrid=H,e.FixedSizeList=U,e.areEqual=N,e.shouldComponentUpdate=function(e,t){return!N(this.props,e)||q(this.state,t)},Object.defineProperty(e,"__esModule",{value:!0})});
+//# sourceMappingURL=index-dev.umd.js.map
diff --git a/vendor/react-window/dist/index-prod.umd.js b/vendor/react-window/dist/index-prod.umd.js
new file mode 100644
index 0000000000000..ca33541ed54f6
--- /dev/null
+++ b/vendor/react-window/dist/index-prod.umd.js
@@ -0,0 +1,2 @@
+!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("react")):"function"==typeof define&&define.amd?define(["exports","react"],e):e((t=t||self).ReactWindow={},t.React)}(this,function(t,e){"use strict";function r(){return(r=Object.assign||function(t){for(var e=1;e=e?t.call(null):o.id=requestAnimationFrame(n)})};return o}var u=-1;var f=null;function d(t){if(void 0===t&&(t=!1),null===f||t){var e=document.createElement("div"),r=e.style;r.width="50px",r.height="50px",r.overflow="scroll",r.direction="rtl";var o=document.createElement("div"),n=o.style;return n.width="100px",n.height="100px",e.appendChild(o),document.body.appendChild(e),e.scrollLeft>0?f="positive-descending":(e.scrollLeft=1,f=0===e.scrollLeft?"negative":"positive-ascending"),document.body.removeChild(e),f}return f}var h=150,m=function(t){var e=t.columnIndex;t.data;return t.rowIndex+":"+e};function p(t){var i,l,f=t.getColumnOffset,p=t.getColumnStartIndexForOffset,v=t.getColumnStopIndexForStartIndex,S=t.getColumnWidth,I=t.getEstimatedTotalHeight,w=t.getEstimatedTotalWidth,M=t.getOffsetForColumnAndAlignment,x=t.getOffsetForRowAndAlignment,_=t.getRowHeight,C=t.getRowOffset,R=t.getRowStartIndexForOffset,y=t.getRowStopIndexForStartIndex,T=t.initInstanceProps,O=t.shouldResetStyleCacheOnItemSizeChange,z=t.validateProps;return l=i=function(t){function i(e){var r;return(r=t.call(this,e)||this)._instanceProps=T(r.props,n(n(r))),r._resetIsScrollingTimeoutId=null,r._outerRef=void 0,r.state={instance:n(n(r)),isScrolling:!1,horizontalScrollDirection:"forward",scrollLeft:"number"==typeof r.props.initialScrollLeft?r.props.initialScrollLeft:0,scrollTop:"number"==typeof r.props.initialScrollTop?r.props.initialScrollTop:0,scrollUpdateWasRequested:!1,verticalScrollDirection:"forward"},r._callOnItemsRendered=void 0,r._callOnItemsRendered=a(function(t,e,o,n,i,a,l,s){return r.props.onItemsRendered({overscanColumnStartIndex:t,overscanColumnStopIndex:e,overscanRowStartIndex:o,overscanRowStopIndex:n,visibleColumnStartIndex:i,visibleColumnStopIndex:a,visibleRowStartIndex:l,visibleRowStopIndex:s})}),r._callOnScroll=void 0,r._callOnScroll=a(function(t,e,o,n,i){return r.props.onScroll({horizontalScrollDirection:o,scrollLeft:t,scrollTop:e,verticalScrollDirection:n,scrollUpdateWasRequested:i})}),r._getItemStyle=void 0,r._getItemStyle=function(t,e){var o,n,i=r.props,a=i.columnWidth,l=i.direction,s=i.rowHeight,c=r._getItemStyleCache(O&&a,O&&l,O&&s),u=t+":"+e;c.hasOwnProperty(u)?o=c[u]:c[u]=((n={position:"absolute"})["rtl"===l?"right":"left"]=f(r.props,e,r._instanceProps),n.top=C(r.props,t,r._instanceProps),n.height=_(r.props,t,r._instanceProps),n.width=S(r.props,e,r._instanceProps),o=n);return o},r._getItemStyleCache=void 0,r._getItemStyleCache=a(function(t,e,r){return{}}),r._onScroll=function(t){var e=t.currentTarget,o=e.clientHeight,n=e.clientWidth,i=e.scrollLeft,a=e.scrollTop,l=e.scrollHeight,s=e.scrollWidth;r.setState(function(t){if(t.scrollLeft===i&&t.scrollTop===a)return null;var e=r.props.direction,c=i;if("rtl"===e)switch(d()){case"negative":c=-i;break;case"positive-descending":c=s-n-i}c=Math.max(0,Math.min(c,s-n));var u=Math.max(0,Math.min(a,l-o));return{isScrolling:!0,horizontalScrollDirection:t.scrollLeftc?m:0,v=p>l?m:0;this.scrollTo({scrollLeft:void 0!==o?M(this.props,o,r,d,this._instanceProps,v):d,scrollTop:void 0!==n?x(this.props,n,r,h,this._instanceProps,g):h})},l.componentDidMount=function(){var t=this.props,e=t.initialScrollLeft,r=t.initialScrollTop;if(null!=this._outerRef){var o=this._outerRef;"number"==typeof e&&(o.scrollLeft=e),"number"==typeof r&&(o.scrollTop=r)}this._callPropsCallbacks()},l.componentDidUpdate=function(){var t=this.props.direction,e=this.state,r=e.scrollLeft,o=e.scrollTop;if(e.scrollUpdateWasRequested&&null!=this._outerRef){var n=this._outerRef;if("rtl"===t)switch(d()){case"negative":n.scrollLeft=-r;break;case"positive-ascending":n.scrollLeft=r;break;default:var i=n.clientWidth,a=n.scrollWidth;n.scrollLeft=a-i-r}else n.scrollLeft=Math.max(0,r);n.scrollTop=Math.max(0,o)}this._callPropsCallbacks()},l.componentWillUnmount=function(){null!==this._resetIsScrollingTimeoutId&&s(this._resetIsScrollingTimeoutId)},l.render=function(){var t=this.props,o=t.children,n=t.className,i=t.columnCount,a=t.direction,l=t.height,s=t.innerRef,c=t.innerElementType,u=t.innerTagName,f=t.itemData,d=t.itemKey,h=void 0===d?m:d,p=t.outerElementType,g=t.outerTagName,v=t.rowCount,S=t.style,M=t.useIsScrolling,x=t.width,_=this.state.isScrolling,C=this._getHorizontalRangeToRender(),R=C[0],y=C[1],T=this._getVerticalRangeToRender(),O=T[0],z=T[1],b=[];if(i>0&&v)for(var P=O;P<=z;P++)for(var W=R;W<=y;W++)b.push(e.createElement(o,{columnIndex:W,data:f,isScrolling:M?_:void 0,key:h({columnIndex:W,data:f,rowIndex:P}),rowIndex:P,style:this._getItemStyle(P,W)}));var D=I(this.props,this._instanceProps),F=w(this.props,this._instanceProps);return e.createElement(p||g||"div",{className:n,onScroll:this._onScroll,ref:this._outerRefSetter,style:r({position:"relative",height:l,width:x,overflow:"auto",WebkitOverflowScrolling:"touch",willChange:"transform",direction:a},S)},e.createElement(c||u||"div",{children:b,ref:s,style:{height:D,pointerEvents:_?"none":void 0,width:F}}))},l._callPropsCallbacks=function(){var t=this.props,e=t.columnCount,r=t.onItemsRendered,o=t.onScroll,n=t.rowCount;if("function"==typeof r&&e>0&&n>0){var i=this._getHorizontalRangeToRender(),a=i[0],l=i[1],s=i[2],c=i[3],u=this._getVerticalRangeToRender(),f=u[0],d=u[1],h=u[2],m=u[3];this._callOnItemsRendered(a,l,f,d,s,c,h,m)}if("function"==typeof o){var p=this.state,g=p.horizontalScrollDirection,v=p.scrollLeft,S=p.scrollTop,I=p.scrollUpdateWasRequested,w=p.verticalScrollDirection;this._callOnScroll(v,S,g,w,I)}},l._getHorizontalRangeToRender=function(){var t=this.props,e=t.columnCount,r=t.overscanColumnCount,o=t.overscanColumnsCount,n=t.overscanCount,i=t.rowCount,a=this.state,l=a.horizontalScrollDirection,s=a.isScrolling,c=a.scrollLeft,u=r||o||n||1;if(0===e||0===i)return[0,0,0,0];var f=p(this.props,c,this._instanceProps),d=v(this.props,f,c,this._instanceProps),h=s&&"backward"!==l?1:Math.max(1,u),m=s&&"forward"!==l?1:Math.max(1,u);return[Math.max(0,f-h),Math.max(0,Math.min(e-1,d+m)),f,d]},l._getVerticalRangeToRender=function(){var t=this.props,e=t.columnCount,r=t.overscanCount,o=t.overscanRowCount,n=t.overscanRowsCount,i=t.rowCount,a=this.state,l=a.isScrolling,s=a.verticalScrollDirection,c=a.scrollTop,u=o||n||r||1;if(0===e||0===i)return[0,0,0,0];var f=R(this.props,c,this._instanceProps),d=y(this.props,f,c,this._instanceProps),h=l&&"backward"!==s?1:Math.max(1,u),m=l&&"forward"!==s?1:Math.max(1,u);return[Math.max(0,f-h),Math.max(0,Math.min(i-1,d+m)),f,d]},i}(e.PureComponent),i.defaultProps={direction:"ltr",itemData:void 0,useIsScrolling:!1},l}var g=function(t,e){t.children,t.direction,t.height,t.innerTagName,t.outerTagName,t.overscanColumnsCount,t.overscanCount,t.overscanRowsCount,t.width,e.instance},v=function(t,e){var r=t.rowCount,o=e.rowMetadataMap,n=e.estimatedRowHeight,i=e.lastMeasuredRowIndex,a=0;if(i>=r&&(i=r-1),i>=0){var l=o[i];a=l.offset+l.size}return a+(r-i-1)*n},S=function(t,e){var r=t.columnCount,o=e.columnMetadataMap,n=e.estimatedColumnWidth,i=e.lastMeasuredColumnIndex,a=0;if(i>=r&&(i=r-1),i>=0){var l=o[i];a=l.offset+l.size}return a+(r-i-1)*n},I=function(t,e,r,o){var n,i,a;if("column"===t?(n=o.columnMetadataMap,i=e.columnWidth,a=o.lastMeasuredColumnIndex):(n=o.rowMetadataMap,i=e.rowHeight,a=o.lastMeasuredRowIndex),r>a){var l=0;if(a>=0){var s=n[a];l=s.offset+s.size}for(var c=a+1;c<=r;c++){var u=i(c);n[c]={offset:l,size:u},l+=u}"column"===t?o.lastMeasuredColumnIndex=r:o.lastMeasuredRowIndex=r}return n[r]},w=function(t,e,r,o){var n,i;return"column"===t?(n=r.columnMetadataMap,i=r.lastMeasuredColumnIndex):(n=r.rowMetadataMap,i=r.lastMeasuredRowIndex),(i>0?n[i].offset:0)>=o?M(t,e,r,i,0,o):x(t,e,r,Math.max(0,i),o)},M=function(t,e,r,o,n,i){for(;n<=o;){var a=n+Math.floor((o-n)/2),l=I(t,e,a,r).offset;if(l===i)return a;li&&(o=a-1)}return n>0?n-1:0},x=function(t,e,r,o,n){for(var i="column"===t?e.columnCount:e.rowCount,a=1;o=f-l&&n<=u+l?"auto":"center"),o){case"start":return u;case"end":return f;case"center":return Math.round(f+(u-f)/2);case"auto":default:return n>=f&&n<=u?n:f>u?f:n0)for(var z=R;z<=T;z++)O.push(e.createElement(o,{data:d,key:m(z,d),index:z,isScrolling:I?M:void 0,style:this._getItemStyle(z)}));var b=f(this.props,this._instanceProps);return e.createElement(g||v||"div",{className:n,onScroll:_,ref:this._outerRefSetter,style:r({position:"relative",height:a,width:w,overflow:"auto",WebkitOverflowScrolling:"touch",willChange:"transform",direction:i},S)},e.createElement(s||c||"div",{children:O,ref:l,style:{height:x?"100%":b,pointerEvents:M?"none":void 0,width:x?b:"100%"}}))},l._callPropsCallbacks=function(){if("function"==typeof this.props.onItemsRendered&&this.props.itemCount>0){var t=this._getRangeToRender(),e=t[0],r=t[1],o=t[2],n=t[3];this._callOnItemsRendered(e,r,o,n)}if("function"==typeof this.props.onScroll){var i=this.state,a=i.scrollDirection,l=i.scrollOffset,s=i.scrollUpdateWasRequested;this._callOnScroll(a,l,s)}},l._getRangeToRender=function(){var t=this.props,e=t.itemCount,r=t.overscanCount,o=this.state,n=o.isScrolling,i=o.scrollDirection,a=o.scrollOffset;if(0===e)return[0,0,0,0];var l=p(this.props,a,this._instanceProps),s=g(this.props,l,a,this._instanceProps),c=n&&"backward"!==i?1:Math.max(1,r),u=n&&"forward"!==i?1:Math.max(1,r);return[Math.max(0,l-c),Math.max(0,Math.min(e-1,s+u)),l,s]},i}(e.PureComponent),i.defaultProps={direction:"ltr",itemData:void 0,layout:"vertical",overscanCount:2,useIsScrolling:!1},l}var O=function(t,e){t.children,t.direction,t.height,t.layout,t.innerTagName,t.outerTagName,t.width,e.instance},z=function(t,e,r){var o=t.itemSize,n=r.itemMetadataMap,i=r.lastMeasuredIndex;if(e>i){var a=0;if(i>=0){var l=n[i];a=l.offset+l.size}for(var s=i+1;s<=e;s++){var c=o(s);n[s]={offset:a,size:c},a+=c}r.lastMeasuredIndex=e}return n[e]},b=function(t,e,r,o,n){for(;o<=r;){var i=o+Math.floor((r-o)/2),a=z(t,i,e).offset;if(a===n)return i;an&&(r=i-1)}return o>0?o-1:0},P=function(t,e,r,o){for(var n=t.itemCount,i=1;r=r&&(i=r-1),i>=0){var l=o[i];a=l.offset+l.size}return a+(r-i-1)*n},D=T({getItemOffset:function(t,e,r){return z(t,e,r).offset},getItemSize:function(t,e,r){return r.itemMetadataMap[e].size},getEstimatedTotalSize:W,getOffsetForIndexAndAlignment:function(t,e,r,o,n){var i=t.direction,a=t.height,l=t.layout,s=t.width,c="horizontal"===i||"horizontal"===l?s:a,u=z(t,e,n),f=W(t,n),d=Math.max(0,Math.min(f-c,u.offset)),h=Math.max(0,u.offset-c+u.size);switch("smart"===r&&(r=o>=h-c&&o<=d+c?"auto":"center"),r){case"start":return d;case"end":return h;case"center":return Math.round(h+(d-h)/2);case"auto":default:return o>=h&&o<=d?o:o0?o[n].offset:0)>=r?b(t,e,n,0,r):P(t,e,Math.max(0,n),r)}(t,r,e)},getStopIndexForStartIndex:function(t,e,r,o){for(var n=t.direction,i=t.height,a=t.itemCount,l=t.layout,s=t.width,c="horizontal"===n||"horizontal"===l?s:i,u=z(t,e,o),f=r+c,d=u.offset+u.size,h=e;h=f-s&&o<=u+s?"auto":"center"),r){case"start":return u;case"end":return f;case"center":var d=Math.round(f+(u-f)/2);return dc+Math.floor(s/2)?c:d;case"auto":default:return o>=f&&o<=u?o:f>u?f:o=f-l&&o<=u+l?"auto":"center"),r){case"start":return u;case"end":return f;case"center":var d=Math.round(f+(u-f)/2);return dc+Math.floor(l/2)?c:d;case"auto":default:return o>=f&&o<=u?o:f>u?f:o=h-u&&o<=d+u?"auto":"center"),r){case"start":return d;case"end":return h;case"center":var m=Math.round(h+(d-h)/2);return mf+Math.floor(u/2)?f:m;case"auto":default:return o>=h&&o<=d?o:o=0||(n[r]=t[r]);return n}function H(t,e){for(var r in t)if(!(r in e))return!0;for(var o in e)if(t[o]!==e[o])return!0;return!1}function k(t,e){var r=t.style,o=A(t,["style"]),n=e.style,i=A(e,["style"]);return!H(r,n)&&!H(o,i)}t.VariableSizeGrid=C,t.VariableSizeList=D,t.FixedSizeGrid=F,t.FixedSizeList=L,t.areEqual=k,t.shouldComponentUpdate=function(t,e){return!k(this.props,t)||H(this.state,e)},Object.defineProperty(t,"__esModule",{value:!0})});
+//# sourceMappingURL=index-prod.umd.js.map
diff --git a/vendor/react-window/dist/index.cjs.js b/vendor/react-window/dist/index.cjs.js
index 08582cdb6fc5d..83875b5ee0193 100644
--- a/vendor/react-window/dist/index.cjs.js
+++ b/vendor/react-window/dist/index.cjs.js
@@ -59,6 +59,50 @@ function getScrollbarSize(recalculate) {
return size;
}
+var cachedRTLResult = null; // TRICKY According to the spec, scrollLeft should be negative for RTL aligned elements.
+// Chrome does not seem to adhere; its scrollLeft values are positive (measured relative to the left).
+// Safari's elastic bounce makes detecting this even more complicated wrt potential false positives.
+// The safest way to check this is to intentionally set a negative offset,
+// and then verify that the subsequent "scroll" event matches the negative offset.
+// If it does not match, then we can assume a non-standard RTL scroll implementation.
+
+function getRTLOffsetType(recalculate) {
+ if (recalculate === void 0) {
+ recalculate = false;
+ }
+
+ if (cachedRTLResult === null || recalculate) {
+ var outerDiv = document.createElement('div');
+ var outerStyle = outerDiv.style;
+ outerStyle.width = '50px';
+ outerStyle.height = '50px';
+ outerStyle.overflow = 'scroll';
+ outerStyle.direction = 'rtl';
+ var innerDiv = document.createElement('div');
+ var innerStyle = innerDiv.style;
+ innerStyle.width = '100px';
+ innerStyle.height = '100px';
+ outerDiv.appendChild(innerDiv);
+ document.body.appendChild(outerDiv);
+
+ if (outerDiv.scrollLeft > 0) {
+ cachedRTLResult = 'positive-descending';
+ } else {
+ outerDiv.scrollLeft = 1;
+
+ if (outerDiv.scrollLeft === 0) {
+ cachedRTLResult = 'negative';
+ } else {
+ cachedRTLResult = 'positive-ascending';
+ }
+ }
+
+ document.body.removeChild(outerDiv);
+ return cachedRTLResult;
+ }
+
+ return cachedRTLResult;
+}
var IS_SCROLLING_DEBOUNCE_INTERVAL = 150;
@@ -72,6 +116,7 @@ var defaultItemKey = function defaultItemKey(_ref) {
var devWarningsOverscanCount = null;
+var devWarningsOverscanRowsColumnsCount = null;
var devWarningsTagName = null;
if (process.env.NODE_ENV !== 'production') {
@@ -79,6 +124,9 @@ if (process.env.NODE_ENV !== 'production') {
devWarningsOverscanCount =
/*#__PURE__*/
new WeakSet();
+ devWarningsOverscanRowsColumnsCount =
+ /*#__PURE__*/
+ new WeakSet();
devWarningsTagName =
/*#__PURE__*/
new WeakSet();
@@ -183,9 +231,11 @@ function createGridComponent(_ref2) {
_this._onScroll = function (event) {
var _event$currentTarget = event.currentTarget,
+ clientHeight = _event$currentTarget.clientHeight,
clientWidth = _event$currentTarget.clientWidth,
scrollLeft = _event$currentTarget.scrollLeft,
scrollTop = _event$currentTarget.scrollTop,
+ scrollHeight = _event$currentTarget.scrollHeight,
scrollWidth = _event$currentTarget.scrollWidth;
_this.setState(function (prevState) {
@@ -196,25 +246,33 @@ function createGridComponent(_ref2) {
return null;
}
- var direction = _this.props.direction; // HACK According to the spec, scrollLeft should be negative for RTL aligned elements.
- // Chrome does not seem to adhere; its scrollLeft values are positive (measured relative to the left).
- // See https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollLeft
+ var direction = _this.props.direction; // TRICKY According to the spec, scrollLeft should be negative for RTL aligned elements.
+ // This is not the case for all browsers though (e.g. Chrome reports values as positive, measured relative to the left).
+ // It's also easier for this component if we convert offsets to the same format as they would be in for ltr.
+ // So the simplest solution is to determine which browser behavior we're dealing with, and convert based on it.
var calculatedScrollLeft = scrollLeft;
if (direction === 'rtl') {
- if (scrollLeft <= 0) {
- calculatedScrollLeft = -scrollLeft;
- } else {
- calculatedScrollLeft = scrollWidth - clientWidth - scrollLeft;
+ switch (getRTLOffsetType()) {
+ case 'negative':
+ calculatedScrollLeft = -scrollLeft;
+ break;
+
+ case 'positive-descending':
+ calculatedScrollLeft = scrollWidth - clientWidth - scrollLeft;
+ break;
}
- }
+ } // Prevent Safari's elastic scrolling from causing visual shaking when scrolling past bounds.
+
+ calculatedScrollLeft = Math.max(0, Math.min(calculatedScrollLeft, scrollWidth - clientWidth));
+ var calculatedScrollTop = Math.max(0, Math.min(scrollTop, scrollHeight - clientHeight));
return {
isScrolling: true,
horizontalScrollDirection: prevState.scrollLeft < scrollLeft ? 'forward' : 'backward',
scrollLeft: calculatedScrollLeft,
- scrollTop: scrollTop,
+ scrollTop: calculatedScrollTop,
verticalScrollDirection: prevState.scrollTop < scrollTop ? 'forward' : 'backward',
scrollUpdateWasRequested: false
};
@@ -339,26 +397,55 @@ function createGridComponent(_ref2) {
initialScrollLeft = _this$props3.initialScrollLeft,
initialScrollTop = _this$props3.initialScrollTop;
- if (typeof initialScrollLeft === 'number' && this._outerRef != null) {
- this._outerRef.scrollLeft = initialScrollLeft;
- }
+ if (this._outerRef != null) {
+ var outerRef = this._outerRef;
+
+ if (typeof initialScrollLeft === 'number') {
+ outerRef.scrollLeft = initialScrollLeft;
+ }
- if (typeof initialScrollTop === 'number' && this._outerRef != null) {
- this._outerRef.scrollTop = initialScrollTop;
+ if (typeof initialScrollTop === 'number') {
+ outerRef.scrollTop = initialScrollTop;
+ }
}
this._callPropsCallbacks();
};
_proto.componentDidUpdate = function componentDidUpdate() {
+ var direction = this.props.direction;
var _this$state2 = this.state,
scrollLeft = _this$state2.scrollLeft,
scrollTop = _this$state2.scrollTop,
scrollUpdateWasRequested = _this$state2.scrollUpdateWasRequested;
- if (scrollUpdateWasRequested && this._outerRef !== null) {
- this._outerRef.scrollLeft = scrollLeft;
- this._outerRef.scrollTop = scrollTop;
+ if (scrollUpdateWasRequested && this._outerRef != null) {
+ // TRICKY According to the spec, scrollLeft should be negative for RTL aligned elements.
+ // This is not the case for all browsers though (e.g. Chrome reports values as positive, measured relative to the left).
+ // So we need to determine which browser behavior we're dealing with, and mimic it.
+ var outerRef = this._outerRef;
+
+ if (direction === 'rtl') {
+ switch (getRTLOffsetType()) {
+ case 'negative':
+ outerRef.scrollLeft = -scrollLeft;
+ break;
+
+ case 'positive-ascending':
+ outerRef.scrollLeft = scrollLeft;
+ break;
+
+ default:
+ var clientWidth = outerRef.clientWidth,
+ scrollWidth = outerRef.scrollWidth;
+ outerRef.scrollLeft = scrollWidth - clientWidth - scrollLeft;
+ break;
+ }
+ } else {
+ outerRef.scrollLeft = Math.max(0, scrollLeft);
+ }
+
+ outerRef.scrollTop = Math.max(0, scrollTop);
}
this._callPropsCallbacks();
@@ -442,7 +529,7 @@ function createGridComponent(_ref2) {
ref: innerRef,
style: {
height: estimatedTotalHeight,
- pointerEvents: isScrolling ? 'none' : '',
+ pointerEvents: isScrolling ? 'none' : undefined,
width: estimatedTotalWidth
}
}));
@@ -492,6 +579,7 @@ function createGridComponent(_ref2) {
_proto._getHorizontalRangeToRender = function _getHorizontalRangeToRender() {
var _this$props6 = this.props,
columnCount = _this$props6.columnCount,
+ overscanColumnCount = _this$props6.overscanColumnCount,
overscanColumnsCount = _this$props6.overscanColumnsCount,
overscanCount = _this$props6.overscanCount,
rowCount = _this$props6.rowCount;
@@ -499,7 +587,7 @@ function createGridComponent(_ref2) {
horizontalScrollDirection = _this$state4.horizontalScrollDirection,
isScrolling = _this$state4.isScrolling,
scrollLeft = _this$state4.scrollLeft;
- var overscanCountResolved = overscanColumnsCount || overscanCount || 1;
+ var overscanCountResolved = overscanColumnCount || overscanColumnsCount || overscanCount || 1;
if (columnCount === 0 || rowCount === 0) {
return [0, 0, 0, 0];
@@ -518,13 +606,14 @@ function createGridComponent(_ref2) {
var _this$props7 = this.props,
columnCount = _this$props7.columnCount,
overscanCount = _this$props7.overscanCount,
+ overscanRowCount = _this$props7.overscanRowCount,
overscanRowsCount = _this$props7.overscanRowsCount,
rowCount = _this$props7.rowCount;
var _this$state5 = this.state,
isScrolling = _this$state5.isScrolling,
verticalScrollDirection = _this$state5.verticalScrollDirection,
scrollTop = _this$state5.scrollTop;
- var overscanCountResolved = overscanRowsCount || overscanCount || 1;
+ var overscanCountResolved = overscanRowCount || overscanRowsCount || overscanCount || 1;
if (columnCount === 0 || rowCount === 0) {
return [0, 0, 0, 0];
@@ -553,7 +642,9 @@ var validateSharedProps = function validateSharedProps(_ref5, _ref6) {
height = _ref5.height,
innerTagName = _ref5.innerTagName,
outerTagName = _ref5.outerTagName,
+ overscanColumnsCount = _ref5.overscanColumnsCount,
overscanCount = _ref5.overscanCount,
+ overscanRowsCount = _ref5.overscanRowsCount,
width = _ref5.width;
var instance = _ref6.instance;
@@ -561,7 +652,14 @@ var validateSharedProps = function validateSharedProps(_ref5, _ref6) {
if (typeof overscanCount === 'number') {
if (devWarningsOverscanCount && !devWarningsOverscanCount.has(instance)) {
devWarningsOverscanCount.add(instance);
- console.warn('The overscanCount prop has been deprecated. ' + 'Please use the overscanColumnsCount and overscanRowsCount props instead.');
+ console.warn('The overscanCount prop has been deprecated. ' + 'Please use the overscanColumnCount and overscanRowCount props instead.');
+ }
+ }
+
+ if (typeof overscanColumnsCount === 'number' || typeof overscanRowsCount === 'number') {
+ if (devWarningsOverscanRowsColumnsCount && !devWarningsOverscanRowsColumnsCount.has(instance)) {
+ devWarningsOverscanRowsColumnsCount.add(instance);
+ console.warn('The overscanColumnsCount and overscanRowsCount props have been deprecated. ' + 'Please use the overscanColumnCount and overscanRowCount props instead.');
}
}
@@ -770,7 +868,11 @@ var getOffsetForIndexAndAlignment = function getOffsetForIndexAndAlignment(itemT
default:
if (scrollOffset >= minOffset && scrollOffset <= maxOffset) {
return scrollOffset;
- } else if (scrollOffset - minOffset < maxOffset - scrollOffset) {
+ } else if (minOffset > maxOffset) {
+ // Because we only take into account the scrollbar size when calculating minOffset
+ // this value can be larger than maxOffset when at the end of the list
+ return minOffset;
+ } else if (scrollOffset < minOffset) {
return minOffset;
} else {
return maxOffset;
@@ -1037,20 +1139,27 @@ function createListComponent(_ref) {
return null;
}
- var direction = _this.props.direction; // HACK According to the spec, scrollLeft should be negative for RTL aligned elements.
- // Chrome does not seem to adhere; its scrolLeft values are positive (measured relative to the left).
- // See https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollLeft
-
+ var direction = _this.props.direction;
var scrollOffset = scrollLeft;
if (direction === 'rtl') {
- if (scrollLeft <= 0) {
- scrollOffset = -scrollOffset;
- } else {
- scrollOffset = scrollWidth - clientWidth - scrollLeft;
+ // TRICKY According to the spec, scrollLeft should be negative for RTL aligned elements.
+ // This is not the case for all browsers though (e.g. Chrome reports values as positive, measured relative to the left).
+ // It's also easier for this component if we convert offsets to the same format as they would be in for ltr.
+ // So the simplest solution is to determine which browser behavior we're dealing with, and convert based on it.
+ switch (getRTLOffsetType()) {
+ case 'negative':
+ scrollOffset = -scrollLeft;
+ break;
+
+ case 'positive-descending':
+ scrollOffset = scrollWidth - clientWidth - scrollLeft;
+ break;
}
- }
+ } // Prevent Safari's elastic scrolling from causing visual shaking when scrolling past bounds.
+
+ scrollOffset = Math.max(0, Math.min(scrollOffset, scrollWidth - clientWidth));
return {
isScrolling: true,
scrollDirection: prevState.scrollOffset < scrollLeft ? 'forward' : 'backward',
@@ -1061,7 +1170,10 @@ function createListComponent(_ref) {
};
_this._onScrollVertical = function (event) {
- var scrollTop = event.currentTarget.scrollTop;
+ var _event$currentTarget2 = event.currentTarget,
+ clientHeight = _event$currentTarget2.clientHeight,
+ scrollHeight = _event$currentTarget2.scrollHeight,
+ scrollTop = _event$currentTarget2.scrollTop;
_this.setState(function (prevState) {
if (prevState.scrollOffset === scrollTop) {
@@ -1069,12 +1181,14 @@ function createListComponent(_ref) {
// In which case we don't need to trigger another render,
// And we don't want to update state.isScrolling.
return null;
- }
+ } // Prevent Safari's elastic scrolling from causing visual shaking when scrolling past bounds.
+
+ var scrollOffset = Math.max(0, Math.min(scrollTop, scrollHeight - clientHeight));
return {
isScrolling: true,
- scrollDirection: prevState.scrollOffset < scrollTop ? 'forward' : 'backward',
- scrollOffset: scrollTop,
+ scrollDirection: prevState.scrollOffset < scrollOffset ? 'forward' : 'backward',
+ scrollOffset: scrollOffset,
scrollUpdateWasRequested: false
};
}, _this._resetIsScrollingDebounced);
@@ -1154,12 +1268,13 @@ function createListComponent(_ref) {
initialScrollOffset = _this$props2.initialScrollOffset,
layout = _this$props2.layout;
- if (typeof initialScrollOffset === 'number' && this._outerRef !== null) {
- // TODO Deprecate direction "horizontal"
+ if (typeof initialScrollOffset === 'number' && this._outerRef != null) {
+ var outerRef = this._outerRef; // TODO Deprecate direction "horizontal"
+
if (direction === 'horizontal' || layout === 'horizontal') {
- this._outerRef.scrollLeft = initialScrollOffset;
+ outerRef.scrollLeft = initialScrollOffset;
} else {
- this._outerRef.scrollTop = initialScrollOffset;
+ outerRef.scrollTop = initialScrollOffset;
}
}
@@ -1174,12 +1289,34 @@ function createListComponent(_ref) {
scrollOffset = _this$state.scrollOffset,
scrollUpdateWasRequested = _this$state.scrollUpdateWasRequested;
- if (scrollUpdateWasRequested && this._outerRef !== null) {
- // TODO Deprecate direction "horizontal"
+ if (scrollUpdateWasRequested && this._outerRef != null) {
+ var outerRef = this._outerRef; // TODO Deprecate direction "horizontal"
+
if (direction === 'horizontal' || layout === 'horizontal') {
- this._outerRef.scrollLeft = scrollOffset;
+ if (direction === 'rtl') {
+ // TRICKY According to the spec, scrollLeft should be negative for RTL aligned elements.
+ // This is not the case for all browsers though (e.g. Chrome reports values as positive, measured relative to the left).
+ // So we need to determine which browser behavior we're dealing with, and mimic it.
+ switch (getRTLOffsetType()) {
+ case 'negative':
+ outerRef.scrollLeft = -scrollOffset;
+ break;
+
+ case 'positive-ascending':
+ outerRef.scrollLeft = scrollOffset;
+ break;
+
+ default:
+ var clientWidth = outerRef.clientWidth,
+ scrollWidth = outerRef.scrollWidth;
+ outerRef.scrollLeft = scrollWidth - clientWidth - scrollOffset;
+ break;
+ }
+ } else {
+ outerRef.scrollLeft = scrollOffset;
+ }
} else {
- this._outerRef.scrollTop = scrollOffset;
+ outerRef.scrollTop = scrollOffset;
}
}
@@ -1255,7 +1392,7 @@ function createListComponent(_ref) {
ref: innerRef,
style: {
height: isHorizontal ? '100%' : estimatedTotalSize,
- pointerEvents: isScrolling ? 'none' : '',
+ pointerEvents: isScrolling ? 'none' : undefined,
width: isHorizontal ? estimatedTotalSize : '100%'
}
}));
@@ -1537,7 +1674,7 @@ createListComponent({
default:
if (scrollOffset >= minOffset && scrollOffset <= maxOffset) {
return scrollOffset;
- } else if (scrollOffset - minOffset < maxOffset - scrollOffset) {
+ } else if (scrollOffset < minOffset) {
return minOffset;
} else {
return maxOffset;
@@ -1642,7 +1779,8 @@ createGridComponent({
var columnCount = _ref7.columnCount,
columnWidth = _ref7.columnWidth,
width = _ref7.width;
- var maxOffset = Math.max(0, Math.min(columnCount * columnWidth - width, columnIndex * columnWidth));
+ var lastColumnOffset = Math.max(0, columnCount * columnWidth - width);
+ var maxOffset = Math.min(lastColumnOffset, columnIndex * columnWidth);
var minOffset = Math.max(0, columnIndex * columnWidth - width + scrollbarSize + columnWidth);
if (align === 'smart') {
@@ -1661,13 +1799,27 @@ createGridComponent({
return minOffset;
case 'center':
- return Math.round(minOffset + (maxOffset - minOffset) / 2);
+ // "Centered" offset is usually the average of the min and max.
+ // But near the edges of the list, this doesn't hold true.
+ var middleOffset = Math.round(minOffset + (maxOffset - minOffset) / 2);
+
+ if (middleOffset < Math.ceil(width / 2)) {
+ return 0; // near the beginning
+ } else if (middleOffset > lastColumnOffset + Math.floor(width / 2)) {
+ return lastColumnOffset; // near the end
+ } else {
+ return middleOffset;
+ }
case 'auto':
default:
if (scrollLeft >= minOffset && scrollLeft <= maxOffset) {
return scrollLeft;
- } else if (scrollLeft - minOffset < maxOffset - scrollLeft) {
+ } else if (minOffset > maxOffset) {
+ // Because we only take into account the scrollbar size when calculating minOffset
+ // this value can be larger than maxOffset when at the end of the list
+ return minOffset;
+ } else if (scrollLeft < minOffset) {
return minOffset;
} else {
return maxOffset;
@@ -1679,7 +1831,8 @@ createGridComponent({
var rowHeight = _ref8.rowHeight,
height = _ref8.height,
rowCount = _ref8.rowCount;
- var maxOffset = Math.max(0, Math.min(rowCount * rowHeight - height, rowIndex * rowHeight));
+ var lastRowOffset = Math.max(0, rowCount * rowHeight - height);
+ var maxOffset = Math.min(lastRowOffset, rowIndex * rowHeight);
var minOffset = Math.max(0, rowIndex * rowHeight - height + scrollbarSize + rowHeight);
if (align === 'smart') {
@@ -1698,13 +1851,27 @@ createGridComponent({
return minOffset;
case 'center':
- return Math.round(minOffset + (maxOffset - minOffset) / 2);
+ // "Centered" offset is usually the average of the min and max.
+ // But near the edges of the list, this doesn't hold true.
+ var middleOffset = Math.round(minOffset + (maxOffset - minOffset) / 2);
+
+ if (middleOffset < Math.ceil(height / 2)) {
+ return 0; // near the beginning
+ } else if (middleOffset > lastRowOffset + Math.floor(height / 2)) {
+ return lastRowOffset; // near the end
+ } else {
+ return middleOffset;
+ }
case 'auto':
default:
if (scrollTop >= minOffset && scrollTop <= maxOffset) {
return scrollTop;
- } else if (scrollTop - minOffset < maxOffset - scrollTop) {
+ } else if (minOffset > maxOffset) {
+ // Because we only take into account the scrollbar size when calculating minOffset
+ // this value can be larger than maxOffset when at the end of the list
+ return minOffset;
+ } else if (scrollTop < minOffset) {
return minOffset;
} else {
return maxOffset;
@@ -1722,7 +1889,9 @@ createGridComponent({
columnCount = _ref10.columnCount,
width = _ref10.width;
var left = startIndex * columnWidth;
- return Math.max(0, Math.min(columnCount - 1, startIndex + Math.floor((width + (scrollLeft - left)) / columnWidth)));
+ var numVisibleColumns = Math.ceil((width + scrollLeft - left) / columnWidth);
+ return Math.max(0, Math.min(columnCount - 1, startIndex + numVisibleColumns - 1 // -1 is because stop index is inclusive
+ ));
},
getRowStartIndexForOffset: function getRowStartIndexForOffset(_ref11, scrollTop) {
var rowHeight = _ref11.rowHeight,
@@ -1733,8 +1902,10 @@ createGridComponent({
var rowHeight = _ref12.rowHeight,
rowCount = _ref12.rowCount,
height = _ref12.height;
- var left = startIndex * rowHeight;
- return Math.max(0, Math.min(rowCount - 1, startIndex + Math.floor((height + (scrollTop - left)) / rowHeight)));
+ var top = startIndex * rowHeight;
+ var numVisibleRows = Math.ceil((height + scrollTop - top) / rowHeight);
+ return Math.max(0, Math.min(rowCount - 1, startIndex + numVisibleRows - 1 // -1 is because stop index is inclusive
+ ));
},
initInstanceProps: function initInstanceProps(props) {// Noop
},
@@ -1759,13 +1930,11 @@ var FixedSizeList =
/*#__PURE__*/
createListComponent({
getItemOffset: function getItemOffset(_ref, index) {
- var itemSize = _ref.itemSize,
- size = _ref.size;
+ var itemSize = _ref.itemSize;
return index * itemSize;
},
getItemSize: function getItemSize(_ref2, index) {
- var itemSize = _ref2.itemSize,
- size = _ref2.size;
+ var itemSize = _ref2.itemSize;
return itemSize;
},
getEstimatedTotalSize: function getEstimatedTotalSize(_ref3) {
@@ -1783,7 +1952,8 @@ createListComponent({
// TODO Deprecate direction "horizontal"
var isHorizontal = direction === 'horizontal' || layout === 'horizontal';
var size = isHorizontal ? width : height;
- var maxOffset = Math.max(0, Math.min(itemCount * itemSize - size, index * itemSize));
+ var lastItemOffset = Math.max(0, itemCount * itemSize - size);
+ var maxOffset = Math.min(lastItemOffset, index * itemSize);
var minOffset = Math.max(0, index * itemSize - size + itemSize);
if (align === 'smart') {
@@ -1802,13 +1972,25 @@ createListComponent({
return minOffset;
case 'center':
- return Math.round(minOffset + (maxOffset - minOffset) / 2);
+ {
+ // "Centered" offset is usually the average of the min and max.
+ // But near the edges of the list, this doesn't hold true.
+ var middleOffset = Math.round(minOffset + (maxOffset - minOffset) / 2);
+
+ if (middleOffset < Math.ceil(size / 2)) {
+ return 0; // near the beginning
+ } else if (middleOffset > lastItemOffset + Math.floor(size / 2)) {
+ return lastItemOffset; // near the end
+ } else {
+ return middleOffset;
+ }
+ }
case 'auto':
default:
if (scrollOffset >= minOffset && scrollOffset <= maxOffset) {
return scrollOffset;
- } else if (scrollOffset - minOffset < maxOffset - scrollOffset) {
+ } else if (scrollOffset < minOffset) {
return minOffset;
} else {
return maxOffset;
@@ -1832,7 +2014,9 @@ createListComponent({
var isHorizontal = direction === 'horizontal' || layout === 'horizontal';
var offset = startIndex * itemSize;
var size = isHorizontal ? width : height;
- return Math.max(0, Math.min(itemCount - 1, startIndex + Math.floor((size + (scrollOffset - offset)) / itemSize)));
+ var numVisibleItems = Math.ceil((size + scrollOffset - offset) / itemSize);
+ return Math.max(0, Math.min(itemCount - 1, startIndex + numVisibleItems - 1 // -1 is because stop index is inclusive
+ ));
},
initInstanceProps: function initInstanceProps(props) {// Noop
},
@@ -1892,3 +2076,4 @@ exports.FixedSizeGrid = FixedSizeGrid;
exports.FixedSizeList = FixedSizeList;
exports.areEqual = areEqual;
exports.shouldComponentUpdate = shouldComponentUpdate;
+//# sourceMappingURL=index.cjs.js.map
diff --git a/vendor/react-window/dist/index.esm.js b/vendor/react-window/dist/index.esm.js
index 19b1884d12ca4..9cf49546c8916 100644
--- a/vendor/react-window/dist/index.esm.js
+++ b/vendor/react-window/dist/index.esm.js
@@ -54,6 +54,50 @@ function getScrollbarSize(recalculate) {
return size;
}
+var cachedRTLResult = null; // TRICKY According to the spec, scrollLeft should be negative for RTL aligned elements.
+// Chrome does not seem to adhere; its scrollLeft values are positive (measured relative to the left).
+// Safari's elastic bounce makes detecting this even more complicated wrt potential false positives.
+// The safest way to check this is to intentionally set a negative offset,
+// and then verify that the subsequent "scroll" event matches the negative offset.
+// If it does not match, then we can assume a non-standard RTL scroll implementation.
+
+function getRTLOffsetType(recalculate) {
+ if (recalculate === void 0) {
+ recalculate = false;
+ }
+
+ if (cachedRTLResult === null || recalculate) {
+ var outerDiv = document.createElement('div');
+ var outerStyle = outerDiv.style;
+ outerStyle.width = '50px';
+ outerStyle.height = '50px';
+ outerStyle.overflow = 'scroll';
+ outerStyle.direction = 'rtl';
+ var innerDiv = document.createElement('div');
+ var innerStyle = innerDiv.style;
+ innerStyle.width = '100px';
+ innerStyle.height = '100px';
+ outerDiv.appendChild(innerDiv);
+ document.body.appendChild(outerDiv);
+
+ if (outerDiv.scrollLeft > 0) {
+ cachedRTLResult = 'positive-descending';
+ } else {
+ outerDiv.scrollLeft = 1;
+
+ if (outerDiv.scrollLeft === 0) {
+ cachedRTLResult = 'negative';
+ } else {
+ cachedRTLResult = 'positive-ascending';
+ }
+ }
+
+ document.body.removeChild(outerDiv);
+ return cachedRTLResult;
+ }
+
+ return cachedRTLResult;
+}
var IS_SCROLLING_DEBOUNCE_INTERVAL = 150;
@@ -67,6 +111,7 @@ var defaultItemKey = function defaultItemKey(_ref) {
var devWarningsOverscanCount = null;
+var devWarningsOverscanRowsColumnsCount = null;
var devWarningsTagName = null;
if (process.env.NODE_ENV !== 'production') {
@@ -74,6 +119,9 @@ if (process.env.NODE_ENV !== 'production') {
devWarningsOverscanCount =
/*#__PURE__*/
new WeakSet();
+ devWarningsOverscanRowsColumnsCount =
+ /*#__PURE__*/
+ new WeakSet();
devWarningsTagName =
/*#__PURE__*/
new WeakSet();
@@ -178,9 +226,11 @@ function createGridComponent(_ref2) {
_this._onScroll = function (event) {
var _event$currentTarget = event.currentTarget,
+ clientHeight = _event$currentTarget.clientHeight,
clientWidth = _event$currentTarget.clientWidth,
scrollLeft = _event$currentTarget.scrollLeft,
scrollTop = _event$currentTarget.scrollTop,
+ scrollHeight = _event$currentTarget.scrollHeight,
scrollWidth = _event$currentTarget.scrollWidth;
// Force flush sync for scroll updates to reduce visual checkerboarding.
@@ -193,25 +243,33 @@ function createGridComponent(_ref2) {
return null;
}
- var direction = _this.props.direction; // HACK According to the spec, scrollLeft should be negative for RTL aligned elements.
- // Chrome does not seem to adhere; its scrollLeft values are positive (measured relative to the left).
- // See https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollLeft
+ var direction = _this.props.direction; // TRICKY According to the spec, scrollLeft should be negative for RTL aligned elements.
+ // This is not the case for all browsers though (e.g. Chrome reports values as positive, measured relative to the left).
+ // It's also easier for this component if we convert offsets to the same format as they would be in for ltr.
+ // So the simplest solution is to determine which browser behavior we're dealing with, and convert based on it.
var calculatedScrollLeft = scrollLeft;
if (direction === 'rtl') {
- if (scrollLeft <= 0) {
- calculatedScrollLeft = -scrollLeft;
- } else {
- calculatedScrollLeft = scrollWidth - clientWidth - scrollLeft;
+ switch (getRTLOffsetType()) {
+ case 'negative':
+ calculatedScrollLeft = -scrollLeft;
+ break;
+
+ case 'positive-descending':
+ calculatedScrollLeft = scrollWidth - clientWidth - scrollLeft;
+ break;
}
- }
+ } // Prevent Safari's elastic scrolling from causing visual shaking when scrolling past bounds.
+
+ calculatedScrollLeft = Math.max(0, Math.min(calculatedScrollLeft, scrollWidth - clientWidth));
+ var calculatedScrollTop = Math.max(0, Math.min(scrollTop, scrollHeight - clientHeight));
return {
isScrolling: true,
horizontalScrollDirection: prevState.scrollLeft < scrollLeft ? 'forward' : 'backward',
scrollLeft: calculatedScrollLeft,
- scrollTop: scrollTop,
+ scrollTop: calculatedScrollTop,
verticalScrollDirection: prevState.scrollTop < scrollTop ? 'forward' : 'backward',
scrollUpdateWasRequested: false
};
@@ -337,26 +395,55 @@ function createGridComponent(_ref2) {
initialScrollLeft = _this$props3.initialScrollLeft,
initialScrollTop = _this$props3.initialScrollTop;
- if (typeof initialScrollLeft === 'number' && this._outerRef != null) {
- this._outerRef.scrollLeft = initialScrollLeft;
- }
+ if (this._outerRef != null) {
+ var outerRef = this._outerRef;
- if (typeof initialScrollTop === 'number' && this._outerRef != null) {
- this._outerRef.scrollTop = initialScrollTop;
+ if (typeof initialScrollLeft === 'number') {
+ outerRef.scrollLeft = initialScrollLeft;
+ }
+
+ if (typeof initialScrollTop === 'number') {
+ outerRef.scrollTop = initialScrollTop;
+ }
}
this._callPropsCallbacks();
};
_proto.componentDidUpdate = function componentDidUpdate() {
+ var direction = this.props.direction;
var _this$state2 = this.state,
scrollLeft = _this$state2.scrollLeft,
scrollTop = _this$state2.scrollTop,
scrollUpdateWasRequested = _this$state2.scrollUpdateWasRequested;
- if (scrollUpdateWasRequested && this._outerRef !== null) {
- this._outerRef.scrollLeft = scrollLeft;
- this._outerRef.scrollTop = scrollTop;
+ if (scrollUpdateWasRequested && this._outerRef != null) {
+ // TRICKY According to the spec, scrollLeft should be negative for RTL aligned elements.
+ // This is not the case for all browsers though (e.g. Chrome reports values as positive, measured relative to the left).
+ // So we need to determine which browser behavior we're dealing with, and mimic it.
+ var outerRef = this._outerRef;
+
+ if (direction === 'rtl') {
+ switch (getRTLOffsetType()) {
+ case 'negative':
+ outerRef.scrollLeft = -scrollLeft;
+ break;
+
+ case 'positive-ascending':
+ outerRef.scrollLeft = scrollLeft;
+ break;
+
+ default:
+ var clientWidth = outerRef.clientWidth,
+ scrollWidth = outerRef.scrollWidth;
+ outerRef.scrollLeft = scrollWidth - clientWidth - scrollLeft;
+ break;
+ }
+ } else {
+ outerRef.scrollLeft = Math.max(0, scrollLeft);
+ }
+
+ outerRef.scrollTop = Math.max(0, scrollTop);
}
this._callPropsCallbacks();
@@ -440,7 +527,7 @@ function createGridComponent(_ref2) {
ref: innerRef,
style: {
height: estimatedTotalHeight,
- pointerEvents: isScrolling ? 'none' : '',
+ pointerEvents: isScrolling ? 'none' : undefined,
width: estimatedTotalWidth
}
}));
@@ -490,6 +577,7 @@ function createGridComponent(_ref2) {
_proto._getHorizontalRangeToRender = function _getHorizontalRangeToRender() {
var _this$props6 = this.props,
columnCount = _this$props6.columnCount,
+ overscanColumnCount = _this$props6.overscanColumnCount,
overscanColumnsCount = _this$props6.overscanColumnsCount,
overscanCount = _this$props6.overscanCount,
rowCount = _this$props6.rowCount;
@@ -497,7 +585,7 @@ function createGridComponent(_ref2) {
horizontalScrollDirection = _this$state4.horizontalScrollDirection,
isScrolling = _this$state4.isScrolling,
scrollLeft = _this$state4.scrollLeft;
- var overscanCountResolved = overscanColumnsCount || overscanCount || 1;
+ var overscanCountResolved = overscanColumnCount || overscanColumnsCount || overscanCount || 1;
if (columnCount === 0 || rowCount === 0) {
return [0, 0, 0, 0];
@@ -516,13 +604,14 @@ function createGridComponent(_ref2) {
var _this$props7 = this.props,
columnCount = _this$props7.columnCount,
overscanCount = _this$props7.overscanCount,
+ overscanRowCount = _this$props7.overscanRowCount,
overscanRowsCount = _this$props7.overscanRowsCount,
rowCount = _this$props7.rowCount;
var _this$state5 = this.state,
isScrolling = _this$state5.isScrolling,
verticalScrollDirection = _this$state5.verticalScrollDirection,
scrollTop = _this$state5.scrollTop;
- var overscanCountResolved = overscanRowsCount || overscanCount || 1;
+ var overscanCountResolved = overscanRowCount || overscanRowsCount || overscanCount || 1;
if (columnCount === 0 || rowCount === 0) {
return [0, 0, 0, 0];
@@ -551,7 +640,9 @@ var validateSharedProps = function validateSharedProps(_ref5, _ref6) {
height = _ref5.height,
innerTagName = _ref5.innerTagName,
outerTagName = _ref5.outerTagName,
+ overscanColumnsCount = _ref5.overscanColumnsCount,
overscanCount = _ref5.overscanCount,
+ overscanRowsCount = _ref5.overscanRowsCount,
width = _ref5.width;
var instance = _ref6.instance;
@@ -559,7 +650,14 @@ var validateSharedProps = function validateSharedProps(_ref5, _ref6) {
if (typeof overscanCount === 'number') {
if (devWarningsOverscanCount && !devWarningsOverscanCount.has(instance)) {
devWarningsOverscanCount.add(instance);
- console.warn('The overscanCount prop has been deprecated. ' + 'Please use the overscanColumnsCount and overscanRowsCount props instead.');
+ console.warn('The overscanCount prop has been deprecated. ' + 'Please use the overscanColumnCount and overscanRowCount props instead.');
+ }
+ }
+
+ if (typeof overscanColumnsCount === 'number' || typeof overscanRowsCount === 'number') {
+ if (devWarningsOverscanRowsColumnsCount && !devWarningsOverscanRowsColumnsCount.has(instance)) {
+ devWarningsOverscanRowsColumnsCount.add(instance);
+ console.warn('The overscanColumnsCount and overscanRowsCount props have been deprecated. ' + 'Please use the overscanColumnCount and overscanRowCount props instead.');
}
}
@@ -768,7 +866,11 @@ var getOffsetForIndexAndAlignment = function getOffsetForIndexAndAlignment(itemT
default:
if (scrollOffset >= minOffset && scrollOffset <= maxOffset) {
return scrollOffset;
- } else if (scrollOffset - minOffset < maxOffset - scrollOffset) {
+ } else if (minOffset > maxOffset) {
+ // Because we only take into account the scrollbar size when calculating minOffset
+ // this value can be larger than maxOffset when at the end of the list
+ return minOffset;
+ } else if (scrollOffset < minOffset) {
return minOffset;
} else {
return maxOffset;
@@ -1037,20 +1139,27 @@ function createListComponent(_ref) {
return null;
}
- var direction = _this.props.direction; // HACK According to the spec, scrollLeft should be negative for RTL aligned elements.
- // Chrome does not seem to adhere; its scrolLeft values are positive (measured relative to the left).
- // See https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollLeft
-
+ var direction = _this.props.direction;
var scrollOffset = scrollLeft;
if (direction === 'rtl') {
- if (scrollLeft <= 0) {
- scrollOffset = -scrollOffset;
- } else {
- scrollOffset = scrollWidth - clientWidth - scrollLeft;
+ // TRICKY According to the spec, scrollLeft should be negative for RTL aligned elements.
+ // This is not the case for all browsers though (e.g. Chrome reports values as positive, measured relative to the left).
+ // It's also easier for this component if we convert offsets to the same format as they would be in for ltr.
+ // So the simplest solution is to determine which browser behavior we're dealing with, and convert based on it.
+ switch (getRTLOffsetType()) {
+ case 'negative':
+ scrollOffset = -scrollLeft;
+ break;
+
+ case 'positive-descending':
+ scrollOffset = scrollWidth - clientWidth - scrollLeft;
+ break;
}
- }
+ } // Prevent Safari's elastic scrolling from causing visual shaking when scrolling past bounds.
+
+ scrollOffset = Math.max(0, Math.min(scrollOffset, scrollWidth - clientWidth));
return {
isScrolling: true,
scrollDirection: prevState.scrollOffset < scrollLeft ? 'forward' : 'backward',
@@ -1058,11 +1167,14 @@ function createListComponent(_ref) {
scrollUpdateWasRequested: false
};
}, _this._resetIsScrollingDebounced);
- });
- };
+ };
+ });
_this._onScrollVertical = function (event) {
- var scrollTop = event.currentTarget.scrollTop;
+ var _event$currentTarget2 = event.currentTarget,
+ clientHeight = _event$currentTarget2.clientHeight,
+ scrollHeight = _event$currentTarget2.scrollHeight,
+ scrollTop = _event$currentTarget2.scrollTop;
// Force flush sync for scroll updates to reduce visual checkerboarding.
flushSync(() => {
@@ -1072,17 +1184,19 @@ function createListComponent(_ref) {
// In which case we don't need to trigger another render,
// And we don't want to update state.isScrolling.
return null;
- }
+ } // Prevent Safari's elastic scrolling from causing visual shaking when scrolling past bounds.
+
+ var scrollOffset = Math.max(0, Math.min(scrollTop, scrollHeight - clientHeight));
return {
isScrolling: true,
- scrollDirection: prevState.scrollOffset < scrollTop ? 'forward' : 'backward',
- scrollOffset: scrollTop,
+ scrollDirection: prevState.scrollOffset < scrollOffset ? 'forward' : 'backward',
+ scrollOffset: scrollOffset,
scrollUpdateWasRequested: false
};
}, _this._resetIsScrollingDebounced);
- });
- };
+ };
+ });
_this._outerRefSetter = function (ref) {
var outerRef = _this.props.outerRef;
@@ -1158,12 +1272,13 @@ function createListComponent(_ref) {
initialScrollOffset = _this$props2.initialScrollOffset,
layout = _this$props2.layout;
- if (typeof initialScrollOffset === 'number' && this._outerRef !== null) {
- // TODO Deprecate direction "horizontal"
+ if (typeof initialScrollOffset === 'number' && this._outerRef != null) {
+ var outerRef = this._outerRef; // TODO Deprecate direction "horizontal"
+
if (direction === 'horizontal' || layout === 'horizontal') {
- this._outerRef.scrollLeft = initialScrollOffset;
+ outerRef.scrollLeft = initialScrollOffset;
} else {
- this._outerRef.scrollTop = initialScrollOffset;
+ outerRef.scrollTop = initialScrollOffset;
}
}
@@ -1178,12 +1293,34 @@ function createListComponent(_ref) {
scrollOffset = _this$state.scrollOffset,
scrollUpdateWasRequested = _this$state.scrollUpdateWasRequested;
- if (scrollUpdateWasRequested && this._outerRef !== null) {
- // TODO Deprecate direction "horizontal"
+ if (scrollUpdateWasRequested && this._outerRef != null) {
+ var outerRef = this._outerRef; // TODO Deprecate direction "horizontal"
+
if (direction === 'horizontal' || layout === 'horizontal') {
- this._outerRef.scrollLeft = scrollOffset;
+ if (direction === 'rtl') {
+ // TRICKY According to the spec, scrollLeft should be negative for RTL aligned elements.
+ // This is not the case for all browsers though (e.g. Chrome reports values as positive, measured relative to the left).
+ // So we need to determine which browser behavior we're dealing with, and mimic it.
+ switch (getRTLOffsetType()) {
+ case 'negative':
+ outerRef.scrollLeft = -scrollOffset;
+ break;
+
+ case 'positive-ascending':
+ outerRef.scrollLeft = scrollOffset;
+ break;
+
+ default:
+ var clientWidth = outerRef.clientWidth,
+ scrollWidth = outerRef.scrollWidth;
+ outerRef.scrollLeft = scrollWidth - clientWidth - scrollOffset;
+ break;
+ }
+ } else {
+ outerRef.scrollLeft = scrollOffset;
+ }
} else {
- this._outerRef.scrollTop = scrollOffset;
+ outerRef.scrollTop = scrollOffset;
}
}
@@ -1259,7 +1396,7 @@ function createListComponent(_ref) {
ref: innerRef,
style: {
height: isHorizontal ? '100%' : estimatedTotalSize,
- pointerEvents: isScrolling ? 'none' : '',
+ pointerEvents: isScrolling ? 'none' : undefined,
width: isHorizontal ? estimatedTotalSize : '100%'
}
}));
@@ -1541,7 +1678,7 @@ createListComponent({
default:
if (scrollOffset >= minOffset && scrollOffset <= maxOffset) {
return scrollOffset;
- } else if (scrollOffset - minOffset < maxOffset - scrollOffset) {
+ } else if (scrollOffset < minOffset) {
return minOffset;
} else {
return maxOffset;
@@ -1646,7 +1783,8 @@ createGridComponent({
var columnCount = _ref7.columnCount,
columnWidth = _ref7.columnWidth,
width = _ref7.width;
- var maxOffset = Math.max(0, Math.min(columnCount * columnWidth - width, columnIndex * columnWidth));
+ var lastColumnOffset = Math.max(0, columnCount * columnWidth - width);
+ var maxOffset = Math.min(lastColumnOffset, columnIndex * columnWidth);
var minOffset = Math.max(0, columnIndex * columnWidth - width + scrollbarSize + columnWidth);
if (align === 'smart') {
@@ -1665,13 +1803,27 @@ createGridComponent({
return minOffset;
case 'center':
- return Math.round(minOffset + (maxOffset - minOffset) / 2);
+ // "Centered" offset is usually the average of the min and max.
+ // But near the edges of the list, this doesn't hold true.
+ var middleOffset = Math.round(minOffset + (maxOffset - minOffset) / 2);
+
+ if (middleOffset < Math.ceil(width / 2)) {
+ return 0; // near the beginning
+ } else if (middleOffset > lastColumnOffset + Math.floor(width / 2)) {
+ return lastColumnOffset; // near the end
+ } else {
+ return middleOffset;
+ }
case 'auto':
default:
if (scrollLeft >= minOffset && scrollLeft <= maxOffset) {
return scrollLeft;
- } else if (scrollLeft - minOffset < maxOffset - scrollLeft) {
+ } else if (minOffset > maxOffset) {
+ // Because we only take into account the scrollbar size when calculating minOffset
+ // this value can be larger than maxOffset when at the end of the list
+ return minOffset;
+ } else if (scrollLeft < minOffset) {
return minOffset;
} else {
return maxOffset;
@@ -1683,7 +1835,8 @@ createGridComponent({
var rowHeight = _ref8.rowHeight,
height = _ref8.height,
rowCount = _ref8.rowCount;
- var maxOffset = Math.max(0, Math.min(rowCount * rowHeight - height, rowIndex * rowHeight));
+ var lastRowOffset = Math.max(0, rowCount * rowHeight - height);
+ var maxOffset = Math.min(lastRowOffset, rowIndex * rowHeight);
var minOffset = Math.max(0, rowIndex * rowHeight - height + scrollbarSize + rowHeight);
if (align === 'smart') {
@@ -1702,13 +1855,27 @@ createGridComponent({
return minOffset;
case 'center':
- return Math.round(minOffset + (maxOffset - minOffset) / 2);
+ // "Centered" offset is usually the average of the min and max.
+ // But near the edges of the list, this doesn't hold true.
+ var middleOffset = Math.round(minOffset + (maxOffset - minOffset) / 2);
+
+ if (middleOffset < Math.ceil(height / 2)) {
+ return 0; // near the beginning
+ } else if (middleOffset > lastRowOffset + Math.floor(height / 2)) {
+ return lastRowOffset; // near the end
+ } else {
+ return middleOffset;
+ }
case 'auto':
default:
if (scrollTop >= minOffset && scrollTop <= maxOffset) {
return scrollTop;
- } else if (scrollTop - minOffset < maxOffset - scrollTop) {
+ } else if (minOffset > maxOffset) {
+ // Because we only take into account the scrollbar size when calculating minOffset
+ // this value can be larger than maxOffset when at the end of the list
+ return minOffset;
+ } else if (scrollTop < minOffset) {
return minOffset;
} else {
return maxOffset;
@@ -1726,7 +1893,9 @@ createGridComponent({
columnCount = _ref10.columnCount,
width = _ref10.width;
var left = startIndex * columnWidth;
- return Math.max(0, Math.min(columnCount - 1, startIndex + Math.floor((width + (scrollLeft - left)) / columnWidth)));
+ var numVisibleColumns = Math.ceil((width + scrollLeft - left) / columnWidth);
+ return Math.max(0, Math.min(columnCount - 1, startIndex + numVisibleColumns - 1 // -1 is because stop index is inclusive
+ ));
},
getRowStartIndexForOffset: function getRowStartIndexForOffset(_ref11, scrollTop) {
var rowHeight = _ref11.rowHeight,
@@ -1737,8 +1906,10 @@ createGridComponent({
var rowHeight = _ref12.rowHeight,
rowCount = _ref12.rowCount,
height = _ref12.height;
- var left = startIndex * rowHeight;
- return Math.max(0, Math.min(rowCount - 1, startIndex + Math.floor((height + (scrollTop - left)) / rowHeight)));
+ var top = startIndex * rowHeight;
+ var numVisibleRows = Math.ceil((height + scrollTop - top) / rowHeight);
+ return Math.max(0, Math.min(rowCount - 1, startIndex + numVisibleRows - 1 // -1 is because stop index is inclusive
+ ));
},
initInstanceProps: function initInstanceProps(props) {// Noop
},
@@ -1763,13 +1934,11 @@ var FixedSizeList =
/*#__PURE__*/
createListComponent({
getItemOffset: function getItemOffset(_ref, index) {
- var itemSize = _ref.itemSize,
- size = _ref.size;
+ var itemSize = _ref.itemSize;
return index * itemSize;
},
getItemSize: function getItemSize(_ref2, index) {
- var itemSize = _ref2.itemSize,
- size = _ref2.size;
+ var itemSize = _ref2.itemSize;
return itemSize;
},
getEstimatedTotalSize: function getEstimatedTotalSize(_ref3) {
@@ -1787,7 +1956,8 @@ createListComponent({
// TODO Deprecate direction "horizontal"
var isHorizontal = direction === 'horizontal' || layout === 'horizontal';
var size = isHorizontal ? width : height;
- var maxOffset = Math.max(0, Math.min(itemCount * itemSize - size, index * itemSize));
+ var lastItemOffset = Math.max(0, itemCount * itemSize - size);
+ var maxOffset = Math.min(lastItemOffset, index * itemSize);
var minOffset = Math.max(0, index * itemSize - size + itemSize);
if (align === 'smart') {
@@ -1806,13 +1976,25 @@ createListComponent({
return minOffset;
case 'center':
- return Math.round(minOffset + (maxOffset - minOffset) / 2);
+ {
+ // "Centered" offset is usually the average of the min and max.
+ // But near the edges of the list, this doesn't hold true.
+ var middleOffset = Math.round(minOffset + (maxOffset - minOffset) / 2);
+
+ if (middleOffset < Math.ceil(size / 2)) {
+ return 0; // near the beginning
+ } else if (middleOffset > lastItemOffset + Math.floor(size / 2)) {
+ return lastItemOffset; // near the end
+ } else {
+ return middleOffset;
+ }
+ }
case 'auto':
default:
if (scrollOffset >= minOffset && scrollOffset <= maxOffset) {
return scrollOffset;
- } else if (scrollOffset - minOffset < maxOffset - scrollOffset) {
+ } else if (scrollOffset < minOffset) {
return minOffset;
} else {
return maxOffset;
@@ -1836,7 +2018,9 @@ createListComponent({
var isHorizontal = direction === 'horizontal' || layout === 'horizontal';
var offset = startIndex * itemSize;
var size = isHorizontal ? width : height;
- return Math.max(0, Math.min(itemCount - 1, startIndex + Math.floor((size + (scrollOffset - offset)) / itemSize)));
+ var numVisibleItems = Math.ceil((size + scrollOffset - offset) / itemSize);
+ return Math.max(0, Math.min(itemCount - 1, startIndex + numVisibleItems - 1 // -1 is because stop index is inclusive
+ ));
},
initInstanceProps: function initInstanceProps(props) {// Noop
},
@@ -1891,3 +2075,4 @@ function shouldComponentUpdate(nextProps, nextState) {
}
export { VariableSizeGrid, VariableSizeList, FixedSizeGrid, FixedSizeList, areEqual, shouldComponentUpdate };
+//# sourceMappingURL=index.esm.js.map
diff --git a/vendor/react-window/package.json b/vendor/react-window/package.json
index adaea80fdb37d..d10a25a04ffdc 100644
--- a/vendor/react-window/package.json
+++ b/vendor/react-window/package.json
@@ -1,6 +1,6 @@
{
"name": "react-window",
- "version": "1.8.0",
+ "version": "1.8.5",
"description":
"React components for efficiently rendering large, scrollable lists and tabular data",
"author":
@@ -91,7 +91,7 @@
"eslint-plugin-promise": "^3.7.0",
"eslint-plugin-react": "^7.7.0",
"eslint-plugin-standard": "^3.0.1",
- "flow-bin": "^0.80.0",
+ "flow-bin": "^0.103.0",
"gh-pages": "^1.1.0",
"lint-staged": "^7.0.5",
"prettier": "^1.12.1",
@@ -103,6 +103,8 @@
"rollup": "^1.4.1",
"rollup-plugin-babel": "^4.3.2",
"rollup-plugin-commonjs": "^9.2.1",
- "rollup-plugin-node-resolve": "^4.0.1"
+ "rollup-plugin-node-resolve": "^4.0.1",
+ "rollup-plugin-replace": "^2.2.0",
+ "rollup-plugin-terser": "^5.1.0"
}
}
diff --git a/vendor/react-window/src/FixedSizeGrid.js b/vendor/react-window/src/FixedSizeGrid.js
index 452536a9df4b3..685ad33478205 100644
--- a/vendor/react-window/src/FixedSizeGrid.js
+++ b/vendor/react-window/src/FixedSizeGrid.js
@@ -31,12 +31,13 @@ const FixedSizeGrid = createGridComponent({
instanceProps: typeof undefined,
scrollbarSize: number
): number => {
- const maxOffset = Math.max(
+ const lastColumnOffset = Math.max(
0,
- Math.min(
- columnCount * ((columnWidth: any): number) - width,
- columnIndex * ((columnWidth: any): number)
- )
+ columnCount * ((columnWidth: any): number) - width
+ );
+ const maxOffset = Math.min(
+ lastColumnOffset,
+ columnIndex * ((columnWidth: any): number)
);
const minOffset = Math.max(
0,
@@ -60,12 +61,27 @@ const FixedSizeGrid = createGridComponent({
case 'end':
return minOffset;
case 'center':
- return Math.round(minOffset + (maxOffset - minOffset) / 2);
+ // "Centered" offset is usually the average of the min and max.
+ // But near the edges of the list, this doesn't hold true.
+ const middleOffset = Math.round(
+ minOffset + (maxOffset - minOffset) / 2
+ );
+ if (middleOffset < Math.ceil(width / 2)) {
+ return 0; // near the beginning
+ } else if (middleOffset > lastColumnOffset + Math.floor(width / 2)) {
+ return lastColumnOffset; // near the end
+ } else {
+ return middleOffset;
+ }
case 'auto':
default:
if (scrollLeft >= minOffset && scrollLeft <= maxOffset) {
return scrollLeft;
- } else if (scrollLeft - minOffset < maxOffset - scrollLeft) {
+ } else if (minOffset > maxOffset) {
+ // Because we only take into account the scrollbar size when calculating minOffset
+ // this value can be larger than maxOffset when at the end of the list
+ return minOffset;
+ } else if (scrollLeft < minOffset) {
return minOffset;
} else {
return maxOffset;
@@ -81,12 +97,13 @@ const FixedSizeGrid = createGridComponent({
instanceProps: typeof undefined,
scrollbarSize: number
): number => {
- const maxOffset = Math.max(
+ const lastRowOffset = Math.max(
0,
- Math.min(
- rowCount * ((rowHeight: any): number) - height,
- rowIndex * ((rowHeight: any): number)
- )
+ rowCount * ((rowHeight: any): number) - height
+ );
+ const maxOffset = Math.min(
+ lastRowOffset,
+ rowIndex * ((rowHeight: any): number)
);
const minOffset = Math.max(
0,
@@ -110,12 +127,27 @@ const FixedSizeGrid = createGridComponent({
case 'end':
return minOffset;
case 'center':
- return Math.round(minOffset + (maxOffset - minOffset) / 2);
+ // "Centered" offset is usually the average of the min and max.
+ // But near the edges of the list, this doesn't hold true.
+ const middleOffset = Math.round(
+ minOffset + (maxOffset - minOffset) / 2
+ );
+ if (middleOffset < Math.ceil(height / 2)) {
+ return 0; // near the beginning
+ } else if (middleOffset > lastRowOffset + Math.floor(height / 2)) {
+ return lastRowOffset; // near the end
+ } else {
+ return middleOffset;
+ }
case 'auto':
default:
if (scrollTop >= minOffset && scrollTop <= maxOffset) {
return scrollTop;
- } else if (scrollTop - minOffset < maxOffset - scrollTop) {
+ } else if (minOffset > maxOffset) {
+ // Because we only take into account the scrollbar size when calculating minOffset
+ // this value can be larger than maxOffset when at the end of the list
+ return minOffset;
+ } else if (scrollTop < minOffset) {
return minOffset;
} else {
return maxOffset;
@@ -141,14 +173,14 @@ const FixedSizeGrid = createGridComponent({
scrollLeft: number
): number => {
const left = startIndex * ((columnWidth: any): number);
+ const numVisibleColumns = Math.ceil(
+ (width + scrollLeft - left) / ((columnWidth: any): number)
+ );
return Math.max(
0,
Math.min(
columnCount - 1,
- startIndex +
- Math.floor(
- (width + (scrollLeft - left)) / ((columnWidth: any): number)
- )
+ startIndex + numVisibleColumns - 1 // -1 is because stop index is inclusive
)
);
},
@@ -167,13 +199,15 @@ const FixedSizeGrid = createGridComponent({
startIndex: number,
scrollTop: number
): number => {
- const left = startIndex * ((rowHeight: any): number);
+ const top = startIndex * ((rowHeight: any): number);
+ const numVisibleRows = Math.ceil(
+ (height + scrollTop - top) / ((rowHeight: any): number)
+ );
return Math.max(
0,
Math.min(
rowCount - 1,
- startIndex +
- Math.floor((height + (scrollTop - left)) / ((rowHeight: any): number))
+ startIndex + numVisibleRows - 1 // -1 is because stop index is inclusive
)
);
},
diff --git a/vendor/react-window/src/FixedSizeList.js b/vendor/react-window/src/FixedSizeList.js
index 991f9004305bc..0e0fc305bc301 100644
--- a/vendor/react-window/src/FixedSizeList.js
+++ b/vendor/react-window/src/FixedSizeList.js
@@ -5,10 +5,10 @@ import createListComponent from './createListComponent';
import type { Props, ScrollToAlign } from './createListComponent';
const FixedSizeList = createListComponent({
- getItemOffset: ({ itemSize, size }: Props, index: number): number =>
+ getItemOffset: ({ itemSize }: Props, index: number): number =>
index * ((itemSize: any): number),
- getItemSize: ({ itemSize, size }: Props, index: number): number =>
+ getItemSize: ({ itemSize }: Props, index: number): number =>
((itemSize: any): number),
getEstimatedTotalSize: ({ itemCount, itemSize }: Props) =>
@@ -23,12 +23,13 @@ const FixedSizeList = createListComponent({
// TODO Deprecate direction "horizontal"
const isHorizontal = direction === 'horizontal' || layout === 'horizontal';
const size = (((isHorizontal ? width : height): any): number);
- const maxOffset = Math.max(
+ const lastItemOffset = Math.max(
0,
- Math.min(
- itemCount * ((itemSize: any): number) - size,
- index * ((itemSize: any): number)
- )
+ itemCount * ((itemSize: any): number) - size
+ );
+ const maxOffset = Math.min(
+ lastItemOffset,
+ index * ((itemSize: any): number)
);
const minOffset = Math.max(
0,
@@ -51,13 +52,25 @@ const FixedSizeList = createListComponent({
return maxOffset;
case 'end':
return minOffset;
- case 'center':
- return Math.round(minOffset + (maxOffset - minOffset) / 2);
+ case 'center': {
+ // "Centered" offset is usually the average of the min and max.
+ // But near the edges of the list, this doesn't hold true.
+ const middleOffset = Math.round(
+ minOffset + (maxOffset - minOffset) / 2
+ );
+ if (middleOffset < Math.ceil(size / 2)) {
+ return 0; // near the beginning
+ } else if (middleOffset > lastItemOffset + Math.floor(size / 2)) {
+ return lastItemOffset; // near the end
+ } else {
+ return middleOffset;
+ }
+ }
case 'auto':
default:
if (scrollOffset >= minOffset && scrollOffset <= maxOffset) {
return scrollOffset;
- } else if (scrollOffset - minOffset < maxOffset - scrollOffset) {
+ } else if (scrollOffset < minOffset) {
return minOffset;
} else {
return maxOffset;
@@ -83,14 +96,14 @@ const FixedSizeList = createListComponent({
const isHorizontal = direction === 'horizontal' || layout === 'horizontal';
const offset = startIndex * ((itemSize: any): number);
const size = (((isHorizontal ? width : height): any): number);
+ const numVisibleItems = Math.ceil(
+ (size + scrollOffset - offset) / ((itemSize: any): number)
+ );
return Math.max(
0,
Math.min(
itemCount - 1,
- startIndex +
- Math.floor(
- (size + (scrollOffset - offset)) / ((itemSize: any): number)
- )
+ startIndex + numVisibleItems - 1 // -1 is because stop index is inclusive
)
);
},
diff --git a/vendor/react-window/src/VariableSizeGrid.js b/vendor/react-window/src/VariableSizeGrid.js
index a1273e198e0d4..46d59521f1978 100644
--- a/vendor/react-window/src/VariableSizeGrid.js
+++ b/vendor/react-window/src/VariableSizeGrid.js
@@ -274,7 +274,11 @@ const getOffsetForIndexAndAlignment = (
default:
if (scrollOffset >= minOffset && scrollOffset <= maxOffset) {
return scrollOffset;
- } else if (scrollOffset - minOffset < maxOffset - scrollOffset) {
+ } else if (minOffset > maxOffset) {
+ // Because we only take into account the scrollbar size when calculating minOffset
+ // this value can be larger than maxOffset when at the end of the list
+ return minOffset;
+ } else if (scrollOffset < minOffset) {
return minOffset;
} else {
return maxOffset;
diff --git a/vendor/react-window/src/VariableSizeList.js b/vendor/react-window/src/VariableSizeList.js
index cebadc663eb22..f4ad103231017 100644
--- a/vendor/react-window/src/VariableSizeList.js
+++ b/vendor/react-window/src/VariableSizeList.js
@@ -227,7 +227,7 @@ const VariableSizeList = createListComponent({
default:
if (scrollOffset >= minOffset && scrollOffset <= maxOffset) {
return scrollOffset;
- } else if (scrollOffset - minOffset < maxOffset - scrollOffset) {
+ } else if (scrollOffset < minOffset) {
return minOffset;
} else {
return maxOffset;
diff --git a/vendor/react-window/src/createGridComponent.js b/vendor/react-window/src/createGridComponent.js
index c72af855c7b22..f2895b60a4ea3 100644
--- a/vendor/react-window/src/createGridComponent.js
+++ b/vendor/react-window/src/createGridComponent.js
@@ -3,7 +3,7 @@
import memoizeOne from 'memoize-one';
import { createElement, PureComponent } from 'react';
import { cancelTimeout, requestTimeout } from './timer';
-import { getScrollbarSize } from './domHelpers';
+import { getScrollbarSize, getRTLOffsetType } from './domHelpers';
import type { TimeoutID } from './timer';
@@ -46,6 +46,22 @@ type OnScrollCallback = ({
type ScrollEvent = SyntheticEvent;
type ItemStyleCache = { [key: string]: Object };
+type OuterProps = {|
+ children: React$Node,
+ className: string | void,
+ onScroll: ScrollEvent => void,
+ style: {
+ [string]: mixed,
+ },
+|};
+
+type InnerProps = {|
+ children: React$Node,
+ style: {
+ [string]: mixed,
+ },
+|};
+
export type Props = {|
children: RenderComponent,
className?: string,
@@ -56,7 +72,7 @@ export type Props = {|
initialScrollLeft?: number,
initialScrollTop?: number,
innerRef?: any,
- innerElementType?: React$ElementType,
+ innerElementType?: string | React$AbstractComponent,
innerTagName?: string, // deprecated
itemData: T,
itemKey?: (params: {|
@@ -67,11 +83,13 @@ export type Props = {|
onItemsRendered?: OnItemsRenderedCallback,
onScroll?: OnScrollCallback,
outerRef?: any,
- outerElementType?: React$ElementType,
+ outerElementType?: string | React$AbstractComponent,
outerTagName?: string, // deprecated
- overscanColumnsCount?: number,
+ overscanColumnCount?: number,
+ overscanColumnsCount?: number, // deprecated
overscanCount?: number, // deprecated
- overscanRowsCount?: number,
+ overscanRowCount?: number,
+ overscanRowsCount?: number, // deprecated
rowCount: number,
rowHeight: itemSize,
style?: Object,
@@ -130,10 +148,12 @@ const defaultItemKey = ({ columnIndex, data, rowIndex }) =>
// In DEV mode, this Set helps us only log a warning once per component instance.
// This avoids spamming the console every time a render happens.
let devWarningsOverscanCount = null;
+let devWarningsOverscanRowsColumnsCount = null;
let devWarningsTagName = null;
if (process.env.NODE_ENV !== 'production') {
if (typeof window !== 'undefined' && typeof window.WeakSet !== 'undefined') {
devWarningsOverscanCount = new WeakSet();
+ devWarningsOverscanRowsColumnsCount = new WeakSet();
devWarningsTagName = new WeakSet();
}
}
@@ -320,21 +340,47 @@ export default function createGridComponent({
componentDidMount() {
const { initialScrollLeft, initialScrollTop } = this.props;
- if (typeof initialScrollLeft === 'number' && this._outerRef != null) {
- ((this._outerRef: any): HTMLDivElement).scrollLeft = initialScrollLeft;
- }
- if (typeof initialScrollTop === 'number' && this._outerRef != null) {
- ((this._outerRef: any): HTMLDivElement).scrollTop = initialScrollTop;
+
+ if (this._outerRef != null) {
+ const outerRef = ((this._outerRef: any): HTMLElement);
+ if (typeof initialScrollLeft === 'number') {
+ outerRef.scrollLeft = initialScrollLeft;
+ }
+ if (typeof initialScrollTop === 'number') {
+ outerRef.scrollTop = initialScrollTop;
+ }
}
this._callPropsCallbacks();
}
componentDidUpdate() {
+ const { direction } = this.props;
const { scrollLeft, scrollTop, scrollUpdateWasRequested } = this.state;
- if (scrollUpdateWasRequested && this._outerRef !== null) {
- ((this._outerRef: any): HTMLDivElement).scrollLeft = scrollLeft;
- ((this._outerRef: any): HTMLDivElement).scrollTop = scrollTop;
+
+ if (scrollUpdateWasRequested && this._outerRef != null) {
+ // TRICKY According to the spec, scrollLeft should be negative for RTL aligned elements.
+ // This is not the case for all browsers though (e.g. Chrome reports values as positive, measured relative to the left).
+ // So we need to determine which browser behavior we're dealing with, and mimic it.
+ const outerRef = ((this._outerRef: any): HTMLElement);
+ if (direction === 'rtl') {
+ switch (getRTLOffsetType()) {
+ case 'negative':
+ outerRef.scrollLeft = -scrollLeft;
+ break;
+ case 'positive-ascending':
+ outerRef.scrollLeft = scrollLeft;
+ break;
+ default:
+ const { clientWidth, scrollWidth } = outerRef;
+ outerRef.scrollLeft = scrollWidth - clientWidth - scrollLeft;
+ break;
+ }
+ } else {
+ outerRef.scrollLeft = Math.max(0, scrollLeft);
+ }
+
+ outerRef.scrollTop = Math.max(0, scrollTop);
}
this._callPropsCallbacks();
@@ -432,7 +478,7 @@ export default function createGridComponent({
ref: innerRef,
style: {
height: estimatedTotalHeight,
- pointerEvents: isScrolling ? 'none' : '',
+ pointerEvents: isScrolling ? 'none' : undefined,
width: estimatedTotalWidth,
},
})
@@ -586,6 +632,7 @@ export default function createGridComponent({
_getHorizontalRangeToRender(): [number, number, number, number] {
const {
columnCount,
+ overscanColumnCount,
overscanColumnsCount,
overscanCount,
rowCount,
@@ -593,7 +640,7 @@ export default function createGridComponent({
const { horizontalScrollDirection, isScrolling, scrollLeft } = this.state;
const overscanCountResolved: number =
- overscanColumnsCount || overscanCount || 1;
+ overscanColumnCount || overscanColumnsCount || overscanCount || 1;
if (columnCount === 0 || rowCount === 0) {
return [0, 0, 0, 0];
@@ -634,13 +681,14 @@ export default function createGridComponent({
const {
columnCount,
overscanCount,
+ overscanRowCount,
overscanRowsCount,
rowCount,
} = this.props;
const { isScrolling, verticalScrollDirection, scrollTop } = this.state;
const overscanCountResolved: number =
- overscanRowsCount || overscanCount || 1;
+ overscanRowCount || overscanRowsCount || overscanCount || 1;
if (columnCount === 0 || rowCount === 0) {
return [0, 0, 0, 0];
@@ -679,9 +727,11 @@ export default function createGridComponent({
_onScroll = (event: ScrollEvent): void => {
const {
+ clientHeight,
clientWidth,
scrollLeft,
scrollTop,
+ scrollHeight,
scrollWidth,
} = event.currentTarget;
this.setState(prevState => {
@@ -697,24 +747,38 @@ export default function createGridComponent({
const { direction } = this.props;
- // HACK According to the spec, scrollLeft should be negative for RTL aligned elements.
- // Chrome does not seem to adhere; its scrollLeft values are positive (measured relative to the left).
- // See https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollLeft
+ // TRICKY According to the spec, scrollLeft should be negative for RTL aligned elements.
+ // This is not the case for all browsers though (e.g. Chrome reports values as positive, measured relative to the left).
+ // It's also easier for this component if we convert offsets to the same format as they would be in for ltr.
+ // So the simplest solution is to determine which browser behavior we're dealing with, and convert based on it.
let calculatedScrollLeft = scrollLeft;
if (direction === 'rtl') {
- if (scrollLeft <= 0) {
- calculatedScrollLeft = -scrollLeft;
- } else {
- calculatedScrollLeft = scrollWidth - clientWidth - scrollLeft;
+ switch (getRTLOffsetType()) {
+ case 'negative':
+ calculatedScrollLeft = -scrollLeft;
+ break;
+ case 'positive-descending':
+ calculatedScrollLeft = scrollWidth - clientWidth - scrollLeft;
+ break;
}
}
+ // Prevent Safari's elastic scrolling from causing visual shaking when scrolling past bounds.
+ calculatedScrollLeft = Math.max(
+ 0,
+ Math.min(calculatedScrollLeft, scrollWidth - clientWidth)
+ );
+ const calculatedScrollTop = Math.max(
+ 0,
+ Math.min(scrollTop, scrollHeight - clientHeight)
+ );
+
return {
isScrolling: true,
horizontalScrollDirection:
prevState.scrollLeft < scrollLeft ? 'forward' : 'backward',
scrollLeft: calculatedScrollLeft,
- scrollTop,
+ scrollTop: calculatedScrollTop,
verticalScrollDirection:
prevState.scrollTop < scrollTop ? 'forward' : 'backward',
scrollUpdateWasRequested: false,
@@ -768,7 +832,9 @@ const validateSharedProps = (
height,
innerTagName,
outerTagName,
+ overscanColumnsCount,
overscanCount,
+ overscanRowsCount,
width,
}: Props,
{ instance }: State
@@ -779,7 +845,23 @@ const validateSharedProps = (
devWarningsOverscanCount.add(instance);
console.warn(
'The overscanCount prop has been deprecated. ' +
- 'Please use the overscanColumnsCount and overscanRowsCount props instead.'
+ 'Please use the overscanColumnCount and overscanRowCount props instead.'
+ );
+ }
+ }
+
+ if (
+ typeof overscanColumnsCount === 'number' ||
+ typeof overscanRowsCount === 'number'
+ ) {
+ if (
+ devWarningsOverscanRowsColumnsCount &&
+ !devWarningsOverscanRowsColumnsCount.has(instance)
+ ) {
+ devWarningsOverscanRowsColumnsCount.add(instance);
+ console.warn(
+ 'The overscanColumnsCount and overscanRowsCount props have been deprecated. ' +
+ 'Please use the overscanColumnCount and overscanRowCount props instead.'
);
}
}
diff --git a/vendor/react-window/src/createListComponent.js b/vendor/react-window/src/createListComponent.js
index 86696a0b803e6..ae7851e9f402d 100644
--- a/vendor/react-window/src/createListComponent.js
+++ b/vendor/react-window/src/createListComponent.js
@@ -3,6 +3,7 @@
import memoizeOne from 'memoize-one';
import { createElement, PureComponent } from 'react';
import { cancelTimeout, requestTimeout } from './timer';
+import { getRTLOffsetType } from './domHelpers';
import type { TimeoutID } from './timer';
@@ -38,6 +39,22 @@ type onScrollCallback = ({
type ScrollEvent = SyntheticEvent;
type ItemStyleCache = { [index: number]: Object };
+type OuterProps = {|
+ children: React$Node,
+ className: string | void,
+ onScroll: ScrollEvent => void,
+ style: {
+ [string]: mixed,
+ },
+|};
+
+type InnerProps = {|
+ children: React$Node,
+ style: {
+ [string]: mixed,
+ },
+|};
+
export type Props = {|
children: RenderComponent,
className?: string,
@@ -45,7 +62,7 @@ export type Props = {|
height: number | string,
initialScrollOffset?: number,
innerRef?: any,
- innerElementType?: React$ElementType,
+ innerElementType?: string | React$AbstractComponent,
innerTagName?: string, // deprecated
itemCount: number,
itemData: T,
@@ -55,7 +72,7 @@ export type Props = {|
onItemsRendered?: onItemsRenderedCallback,
onScroll?: onScrollCallback,
outerRef?: any,
- outerElementType?: React$ElementType,
+ outerElementType?: string | React$AbstractComponent,
outerTagName?: string, // deprecated
overscanCount: number,
style?: Object,
@@ -215,14 +232,13 @@ export default function createListComponent({
componentDidMount() {
const { direction, initialScrollOffset, layout } = this.props;
- if (typeof initialScrollOffset === 'number' && this._outerRef !== null) {
+ if (typeof initialScrollOffset === 'number' && this._outerRef != null) {
+ const outerRef = ((this._outerRef: any): HTMLElement);
// TODO Deprecate direction "horizontal"
if (direction === 'horizontal' || layout === 'horizontal') {
- ((this
- ._outerRef: any): HTMLDivElement).scrollLeft = initialScrollOffset;
+ outerRef.scrollLeft = initialScrollOffset;
} else {
- ((this
- ._outerRef: any): HTMLDivElement).scrollTop = initialScrollOffset;
+ outerRef.scrollTop = initialScrollOffset;
}
}
@@ -233,12 +249,32 @@ export default function createListComponent({
const { direction, layout } = this.props;
const { scrollOffset, scrollUpdateWasRequested } = this.state;
- if (scrollUpdateWasRequested && this._outerRef !== null) {
+ if (scrollUpdateWasRequested && this._outerRef != null) {
+ const outerRef = ((this._outerRef: any): HTMLElement);
+
// TODO Deprecate direction "horizontal"
if (direction === 'horizontal' || layout === 'horizontal') {
- ((this._outerRef: any): HTMLDivElement).scrollLeft = scrollOffset;
+ if (direction === 'rtl') {
+ // TRICKY According to the spec, scrollLeft should be negative for RTL aligned elements.
+ // This is not the case for all browsers though (e.g. Chrome reports values as positive, measured relative to the left).
+ // So we need to determine which browser behavior we're dealing with, and mimic it.
+ switch (getRTLOffsetType()) {
+ case 'negative':
+ outerRef.scrollLeft = -scrollOffset;
+ break;
+ case 'positive-ascending':
+ outerRef.scrollLeft = scrollOffset;
+ break;
+ default:
+ const { clientWidth, scrollWidth } = outerRef;
+ outerRef.scrollLeft = scrollWidth - clientWidth - scrollOffset;
+ break;
+ }
+ } else {
+ outerRef.scrollLeft = scrollOffset;
+ }
} else {
- ((this._outerRef: any): HTMLDivElement).scrollTop = scrollOffset;
+ outerRef.scrollTop = scrollOffset;
}
}
@@ -326,7 +362,7 @@ export default function createListComponent({
ref: innerRef,
style: {
height: isHorizontal ? '100%' : estimatedTotalSize,
- pointerEvents: isScrolling ? 'none' : '',
+ pointerEvents: isScrolling ? 'none' : undefined,
width: isHorizontal ? estimatedTotalSize : '100%',
},
})
@@ -496,18 +532,28 @@ export default function createListComponent({
const { direction } = this.props;
- // HACK According to the spec, scrollLeft should be negative for RTL aligned elements.
- // Chrome does not seem to adhere; its scrolLeft values are positive (measured relative to the left).
- // See https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollLeft
let scrollOffset = scrollLeft;
if (direction === 'rtl') {
- if (scrollLeft <= 0) {
- scrollOffset = -scrollOffset;
- } else {
- scrollOffset = scrollWidth - clientWidth - scrollLeft;
+ // TRICKY According to the spec, scrollLeft should be negative for RTL aligned elements.
+ // This is not the case for all browsers though (e.g. Chrome reports values as positive, measured relative to the left).
+ // It's also easier for this component if we convert offsets to the same format as they would be in for ltr.
+ // So the simplest solution is to determine which browser behavior we're dealing with, and convert based on it.
+ switch (getRTLOffsetType()) {
+ case 'negative':
+ scrollOffset = -scrollLeft;
+ break;
+ case 'positive-descending':
+ scrollOffset = scrollWidth - clientWidth - scrollLeft;
+ break;
}
}
+ // Prevent Safari's elastic scrolling from causing visual shaking when scrolling past bounds.
+ scrollOffset = Math.max(
+ 0,
+ Math.min(scrollOffset, scrollWidth - clientWidth)
+ );
+
return {
isScrolling: true,
scrollDirection:
@@ -519,7 +565,7 @@ export default function createListComponent({
};
_onScrollVertical = (event: ScrollEvent): void => {
- const { scrollTop } = event.currentTarget;
+ const { clientHeight, scrollHeight, scrollTop } = event.currentTarget;
this.setState(prevState => {
if (prevState.scrollOffset === scrollTop) {
// Scroll position may have been updated by cDM/cDU,
@@ -528,11 +574,17 @@ export default function createListComponent({
return null;
}
+ // Prevent Safari's elastic scrolling from causing visual shaking when scrolling past bounds.
+ const scrollOffset = Math.max(
+ 0,
+ Math.min(scrollTop, scrollHeight - clientHeight)
+ );
+
return {
isScrolling: true,
scrollDirection:
- prevState.scrollOffset < scrollTop ? 'forward' : 'backward',
- scrollOffset: scrollTop,
+ prevState.scrollOffset < scrollOffset ? 'forward' : 'backward',
+ scrollOffset,
scrollUpdateWasRequested: false,
};
}, this._resetIsScrollingDebounced);
diff --git a/vendor/react-window/src/domHelpers.js b/vendor/react-window/src/domHelpers.js
index 830aba68d79aa..1bdc9dddc10aa 100644
--- a/vendor/react-window/src/domHelpers.js
+++ b/vendor/react-window/src/domHelpers.js
@@ -20,3 +20,53 @@ export function getScrollbarSize(recalculate?: boolean = false): number {
return size;
}
+
+export type RTLOffsetType =
+ | 'negative'
+ | 'positive-descending'
+ | 'positive-ascending';
+
+let cachedRTLResult: RTLOffsetType | null = null;
+
+// TRICKY According to the spec, scrollLeft should be negative for RTL aligned elements.
+// Chrome does not seem to adhere; its scrollLeft values are positive (measured relative to the left).
+// Safari's elastic bounce makes detecting this even more complicated wrt potential false positives.
+// The safest way to check this is to intentionally set a negative offset,
+// and then verify that the subsequent "scroll" event matches the negative offset.
+// If it does not match, then we can assume a non-standard RTL scroll implementation.
+export function getRTLOffsetType(recalculate?: boolean = false): RTLOffsetType {
+ if (cachedRTLResult === null || recalculate) {
+ const outerDiv = document.createElement('div');
+ const outerStyle = outerDiv.style;
+ outerStyle.width = '50px';
+ outerStyle.height = '50px';
+ outerStyle.overflow = 'scroll';
+ outerStyle.direction = 'rtl';
+
+ const innerDiv = document.createElement('div');
+ const innerStyle = innerDiv.style;
+ innerStyle.width = '100px';
+ innerStyle.height = '100px';
+
+ outerDiv.appendChild(innerDiv);
+
+ ((document.body: any): HTMLBodyElement).appendChild(outerDiv);
+
+ if (outerDiv.scrollLeft > 0) {
+ cachedRTLResult = 'positive-descending';
+ } else {
+ outerDiv.scrollLeft = 1;
+ if (outerDiv.scrollLeft === 0) {
+ cachedRTLResult = 'negative';
+ } else {
+ cachedRTLResult = 'positive-ascending';
+ }
+ }
+
+ ((document.body: any): HTMLBodyElement).removeChild(outerDiv);
+
+ return cachedRTLResult;
+ }
+
+ return cachedRTLResult;
+}
diff --git a/yarn.lock b/yarn.lock
index 616e6e2645205..76c0f0e882c1c 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -766,9 +766,9 @@
regenerator-runtime "^0.12.0"
"@babel/runtime@^7.0.0":
- version "7.4.5"
- resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.4.5.tgz#582bb531f5f9dc67d2fcb682979894f75e253f12"
- integrity sha512-TuI4qpWZP6lGOGIuGWtp9sPluqYICmbk8T/1vpSysqJxRPkudh/ofFWyqdcMsDf2s7KvDL4/YHgKyvcS3g9CJQ==
+ version "7.5.5"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.5.5.tgz#74fba56d35efbeca444091c7850ccd494fd2f132"
+ integrity sha512-28QvEGyQyNkB0/m2B4FU7IEZGK2NUrcMtT6BZEFALTguLk+AUT6ofsHtPk5QyjAdUkpMJ+/Em+quwz4HOt30AQ==
dependencies:
regenerator-runtime "^0.13.2"
@@ -5522,10 +5522,10 @@ flatstr@^1.0.9:
resolved "https://registry.yarnpkg.com/flatstr/-/flatstr-1.0.9.tgz#0950d56fec02de1030c1311847ecd58c25690eb9"
integrity sha512-qFlJnOBWDfIaunF54/lBqNKmXOI0HqNhu+mHkLmbaBXlS71PUd9OjFOdyevHt/aHoHB1+eW7eKHgRKOG5aHSpw==
-flow-bin@^0.97.0:
- version "0.97.0"
- resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.97.0.tgz#036ffcfc27503367a9d906ec9d843a0aa6f6bb83"
- integrity sha512-jXjD05gkatLuC4+e28frH1hZoRwr1iASP6oJr61Q64+kR4kmzaS+AdFBhYgoYS5kpoe4UzwDebWK8ETQFNh00w==
+flow-bin@^0.103.0:
+ version "0.103.0"
+ resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.103.0.tgz#7aec510d85e1c1b0f2b912bb988337d70035cb0f"
+ integrity sha512-Y3yrnE5ICN1Kl/y10BwjA3JSuS+gt4jVPNyUNCZb0RqmkdssMrW8QNNysJYvhgAY/JBJH8Qv7NVUf11MiwfSlA==
fluent-syntax@0.10.0:
version "0.10.0"
@@ -8250,9 +8250,9 @@ mem@^4.0.0:
p-is-promise "^2.0.0"
"memoize-one@>=3.1.1 <6":
- version "5.0.4"
- resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.0.4.tgz#005928aced5c43d890a4dfab18ca908b0ec92cbc"
- integrity sha512-P0z5IeAH6qHHGkJIXWw0xC2HNEgkx/9uWWBQw64FJj3/ol14VYdfVGWWr0fXfjhhv3TKVIqUq65os6O4GUNksA==
+ version "5.0.5"
+ resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.0.5.tgz#8cd3809555723a07684afafcd6f756072ac75d7e"
+ integrity sha512-ey6EpYv0tEaIbM/nTDOpHciXUvd+ackQrJgEzBwemhZZIWZjcyodqEcrmqDy2BKRTM3a65kKBV4WtLXJDt26SQ==
memoize-one@^3.1.1:
version "3.1.1"
@@ -10183,9 +10183,9 @@ regenerator-runtime@^0.12.0:
integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==
regenerator-runtime@^0.13.2:
- version "0.13.2"
- resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz#32e59c9a6fb9b1a4aff09b4930ca2d4477343447"
- integrity sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA==
+ version "0.13.3"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz#7cf6a77d8f5c6f60eb73c5fc1955b2ceb01e6bf5"
+ integrity sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==
regenerator-runtime@^0.9.5:
version "0.9.6"