mirror of
https://github.com/prymitive/karma
synced 2026-05-09 03:36:44 +00:00
Merge pull request #986 from prymitive/window-resize
fix(ui): better handling of window resize events
This commit is contained in:
@@ -19,7 +19,7 @@ const GetColumnsCount = (canvasWidth, baseWidth) =>
|
||||
.map(gs => gs.columns)
|
||||
.pop();
|
||||
|
||||
const GetGridElementWidth = (canvasWidth, baseWidth) =>
|
||||
Math.floor(canvasWidth / GetColumnsCount(canvasWidth, baseWidth));
|
||||
const GetGridElementWidth = (innerWidth, outerWidth, baseWidth) =>
|
||||
Math.floor(innerWidth / GetColumnsCount(outerWidth, baseWidth));
|
||||
|
||||
export { GridSizesConfig, GetColumnsCount, GetGridElementWidth };
|
||||
|
||||
@@ -39,61 +39,38 @@ const AlertGrid = observer(
|
||||
// and group size
|
||||
this.viewport = observable(
|
||||
{
|
||||
width: document.body.clientWidth,
|
||||
widthAdjust: 0,
|
||||
widthHistory: [],
|
||||
update(width, height) {
|
||||
if (
|
||||
this.widthHistory.length === 4 &&
|
||||
this.widthHistory[0] !== this.widthHistory[1] &&
|
||||
this.widthHistory[0] !== this.widthHistory[3]
|
||||
) {
|
||||
const uniqueWidths = this.widthHistory.reduce((uniques, w) => {
|
||||
const count = uniques[w] || 0;
|
||||
uniques[w] = count + 1;
|
||||
return uniques;
|
||||
}, {});
|
||||
|
||||
if (
|
||||
this.widthHistory.includes(width) &&
|
||||
Object.keys(uniqueWidths).length === 2 &&
|
||||
Object.values(uniqueWidths)[0] ===
|
||||
Object.values(uniqueWidths)[1]
|
||||
) {
|
||||
this.widthAdjust = Math.min(this.widthAdjust + 20, 200);
|
||||
} else {
|
||||
this.widthAdjust = 0;
|
||||
}
|
||||
}
|
||||
|
||||
this.width = width;
|
||||
|
||||
this.widthHistory.unshift(width);
|
||||
this.widthHistory = this.widthHistory.slice(0, 4);
|
||||
canvasWidth: document.body.clientWidth,
|
||||
windowWidth: window.innerWidth,
|
||||
updateWidths(canvasWidth, windowWidth) {
|
||||
this.canvasWidth = canvasWidth;
|
||||
this.windowWidth = windowWidth;
|
||||
},
|
||||
get gridSizesConfig() {
|
||||
return GridSizesConfig(
|
||||
this.width,
|
||||
props.settingsStore.gridConfig.config.groupWidth +
|
||||
this.widthAdjust
|
||||
this.windowWidth,
|
||||
props.settingsStore.gridConfig.config.groupWidth
|
||||
);
|
||||
},
|
||||
get groupWidth() {
|
||||
return GetGridElementWidth(
|
||||
this.width,
|
||||
props.settingsStore.gridConfig.config.groupWidth +
|
||||
this.widthAdjust
|
||||
this.canvasWidth,
|
||||
this.windowWidth,
|
||||
props.settingsStore.gridConfig.config.groupWidth
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
update: action.bound,
|
||||
updateWidths: action.bound,
|
||||
gridSizesConfig: computed,
|
||||
groupWidth: computed
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
handleResize = debounce(() => {
|
||||
this.viewport.updateWidths(document.body.clientWidth, window.innerWidth);
|
||||
}, 100);
|
||||
|
||||
// store reference to generated masonry component so we can call it
|
||||
// to repack the grid after any component was re-rendered, which could
|
||||
// alter its size breaking grid layout
|
||||
@@ -153,6 +130,12 @@ const AlertGrid = observer(
|
||||
// wait up to 30s, run no-op function on timeout
|
||||
font.load(null, 30000).then(this.masonryRepack, () => {});
|
||||
}
|
||||
|
||||
window.addEventListener("resize", this.handleResize);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
window.removeEventListener("resize", this.handleResize);
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -163,13 +146,9 @@ const AlertGrid = observer(
|
||||
<ReactResizeDetector
|
||||
handleWidth
|
||||
handleHeight
|
||||
onResize={debounce(this.viewport.update, 100)}
|
||||
onResize={debounce(this.handleResize, 100)}
|
||||
/>
|
||||
<MasonryInfiniteScroller
|
||||
key={
|
||||
settingsStore.gridConfig.config.groupWidth +
|
||||
this.viewport.widthAdjust
|
||||
}
|
||||
ref={this.storeMasonryRef}
|
||||
position={false}
|
||||
pack={true}
|
||||
|
||||
@@ -75,10 +75,10 @@ const MockGroupList = (count, alertPerGroup) => {
|
||||
alertStore.data.groups = groups;
|
||||
};
|
||||
|
||||
const VerifyColumnCount = (innerWidth, columns) => {
|
||||
const VerifyColumnCount = (innerWidth, outerWidth, columns) => {
|
||||
MockGroupList(60, 5);
|
||||
const tree = ShallowAlertGrid();
|
||||
tree.instance().viewport.update(innerWidth, 500);
|
||||
tree.instance().viewport.updateWidths(innerWidth, outerWidth);
|
||||
expect(
|
||||
tree
|
||||
.find("AlertGroup")
|
||||
@@ -167,22 +167,22 @@ describe("<AlertGrid />", () => {
|
||||
|
||||
// known breakpoints calculated from GridSize logic
|
||||
[
|
||||
{ breakpoint: 400, columns: 1 },
|
||||
{ breakpoint: 800, columns: 2 },
|
||||
{ breakpoint: 1200, columns: 3 },
|
||||
{ breakpoint: 1600, columns: 4 },
|
||||
{ breakpoint: 2000, columns: 5 },
|
||||
{ breakpoint: 2400, columns: 6 },
|
||||
{ breakpoint: 3000, columns: 7 },
|
||||
{ breakpoint: 3400, columns: 8 },
|
||||
{ breakpoint: 3800, columns: 9 },
|
||||
{ breakpoint: 4200, columns: 10 }
|
||||
{ canvas: 400, columns: 1 },
|
||||
{ canvas: 800, columns: 2 },
|
||||
{ canvas: 1200, columns: 3 },
|
||||
{ canvas: 1600, columns: 4 },
|
||||
{ canvas: 2000, columns: 5 },
|
||||
{ canvas: 2400, columns: 6 },
|
||||
{ canvas: 2800, columns: 7 },
|
||||
{ canvas: 3200, columns: 8 },
|
||||
{ canvas: 3600, columns: 9 },
|
||||
{ canvas: 4000, columns: 10 }
|
||||
].map(t =>
|
||||
it(`renders ${t.columns} column(s) on ${t.breakpoint} breakpoint`, () => {
|
||||
it(`renders ${t.columns} column(s) on ${t.canvas} breakpoint`, () => {
|
||||
settingsStore.gridConfig.config.groupWidth = 400;
|
||||
VerifyColumnCount(t.canvas - 1, Math.max(1, t.columns - 1));
|
||||
VerifyColumnCount(t.canvas, t.columns);
|
||||
VerifyColumnCount(t.canvas + 1, t.columns);
|
||||
VerifyColumnCount(t.canvas - 1, t.canvas - 1, Math.max(1, t.columns - 1));
|
||||
VerifyColumnCount(t.canvas, t.canvas, t.columns);
|
||||
VerifyColumnCount(t.canvas + 1, t.canvas + 1, t.columns);
|
||||
})
|
||||
);
|
||||
|
||||
@@ -202,7 +202,7 @@ describe("<AlertGrid />", () => {
|
||||
].map(t =>
|
||||
it(`renders ${t.columns} column(s) with ${t.canvas} resolution`, () => {
|
||||
settingsStore.gridConfig.config.groupWidth = 400;
|
||||
VerifyColumnCount(t.canvas, t.columns);
|
||||
VerifyColumnCount(t.canvas, t.canvas, t.columns);
|
||||
})
|
||||
);
|
||||
|
||||
@@ -211,7 +211,7 @@ describe("<AlertGrid />", () => {
|
||||
let lastColumns = 1;
|
||||
for (let i = 100; i <= 4096; i++) {
|
||||
const expectedColumns = Math.max(Math.floor(i / minWidth), 1);
|
||||
const columns = Math.floor(i / GetGridElementWidth(i, minWidth));
|
||||
const columns = Math.floor(i / GetGridElementWidth(i, i, minWidth));
|
||||
|
||||
expect({
|
||||
resolution: i,
|
||||
@@ -234,7 +234,7 @@ describe("<AlertGrid />", () => {
|
||||
MockGroupList(60, 5);
|
||||
const tree = ShallowAlertGrid();
|
||||
// set initial width
|
||||
tree.instance().viewport.update(1980, 500);
|
||||
tree.instance().viewport.updateWidths(1980, 1980);
|
||||
expect(
|
||||
tree
|
||||
.find("AlertGroup")
|
||||
@@ -243,7 +243,7 @@ describe("<AlertGrid />", () => {
|
||||
).toBe(1980 / 4);
|
||||
|
||||
// then resize and verify if column count was changed
|
||||
tree.instance().viewport.update(1000, 500);
|
||||
tree.instance().viewport.updateWidths(1000, 1000);
|
||||
expect(
|
||||
tree
|
||||
.find("AlertGroup")
|
||||
@@ -252,14 +252,50 @@ describe("<AlertGrid />", () => {
|
||||
).toBe(1000 / 2);
|
||||
});
|
||||
|
||||
it("scrollbar render doesn't resize alert groups", () => {
|
||||
settingsStore.gridConfig.config.groupWidth = 400;
|
||||
|
||||
MockGroupList(60, 5);
|
||||
const tree = ShallowAlertGrid();
|
||||
// set initial width
|
||||
tree.instance().viewport.updateWidths(1600, 1600);
|
||||
expect(
|
||||
tree
|
||||
.find("AlertGroup")
|
||||
.at(0)
|
||||
.props().style.width
|
||||
).toBe(400);
|
||||
|
||||
// then resize and verify if column count was changed
|
||||
tree.instance().viewport.updateWidths(1584, 1600);
|
||||
expect(
|
||||
tree
|
||||
.find("AlertGroup")
|
||||
.at(0)
|
||||
.props().style.width
|
||||
).toBe(396);
|
||||
});
|
||||
|
||||
it("window resize event calls updateWidths", () => {
|
||||
MockGroupList(60, 5);
|
||||
const tree = ShallowAlertGrid();
|
||||
const instance = tree.instance();
|
||||
|
||||
const updateWidthsSpy = jest.spyOn(instance.viewport, "updateWidths");
|
||||
global.dispatchEvent(new Event("resize"));
|
||||
expect(updateWidthsSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("viewport resize doesn't allow loops", () => {
|
||||
settingsStore.gridConfig.config.groupWidth = 410;
|
||||
settingsStore.gridConfig.config.groupWidth = 400;
|
||||
const tree = ShallowAlertGrid();
|
||||
|
||||
let results = [];
|
||||
for (var index = 0; index < 14; index++) {
|
||||
MockGroupList(60, 5);
|
||||
tree.instance().viewport.update(index % 2 === 0 ? 800 : 830, 500);
|
||||
tree
|
||||
.instance()
|
||||
.viewport.updateWidths(index % 2 === 0 ? 1600 : 1584, 1600);
|
||||
results.push(
|
||||
tree
|
||||
.find("AlertGroup")
|
||||
@@ -268,37 +304,22 @@ describe("<AlertGrid />", () => {
|
||||
);
|
||||
}
|
||||
|
||||
// first 4 results will switch beween 1 and 2 columns, but after than it
|
||||
// should stabilise and return same result as the grid width
|
||||
expect(results).toStrictEqual([
|
||||
800,
|
||||
415,
|
||||
800,
|
||||
415,
|
||||
800,
|
||||
830,
|
||||
800,
|
||||
830,
|
||||
800,
|
||||
830,
|
||||
800,
|
||||
830,
|
||||
800,
|
||||
830
|
||||
400,
|
||||
396,
|
||||
400,
|
||||
396,
|
||||
400,
|
||||
396,
|
||||
400,
|
||||
396,
|
||||
400,
|
||||
396,
|
||||
400,
|
||||
396,
|
||||
400,
|
||||
396
|
||||
]);
|
||||
|
||||
// so now let's call it without any loop
|
||||
results = [];
|
||||
for (let width of [840, 820, 450, 450, 1200]) {
|
||||
tree.instance().viewport.update(width, 500);
|
||||
results.push(
|
||||
tree
|
||||
.find("AlertGroup")
|
||||
.at(0)
|
||||
.props().style.width
|
||||
);
|
||||
}
|
||||
expect(results).toStrictEqual([420, 410, 450, 450, 600]);
|
||||
});
|
||||
|
||||
it("doesn't crash on unmount", () => {
|
||||
|
||||
@@ -73,7 +73,6 @@ const MockGroup = (groupName, alertCount, active, suppressed, unprocessed) => {
|
||||
};
|
||||
|
||||
storiesOf("Grid", module)
|
||||
.addDecorator(storyFn => <div className="p-2">{storyFn()}</div>)
|
||||
.add("UpstreamError", () => {
|
||||
return <UpstreamError name="am1" message="Something failed" />;
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user