Skip to content

Commit

Permalink
feat: add infoBy prop for frameworks (#538)
Browse files Browse the repository at this point in the history
* fix: fix inside zone

* feat: check invisible item size

* fix: fix vue commonjs config

* test: test invisible item size

* feat: add infoBy prop for frameworks

* fix: fix itemRenderer

* skip: apply review

* chore: bump @egjs/grid
  • Loading branch information
daybrush committed May 26, 2023
1 parent a2d9dd5 commit 6fd5c0b
Show file tree
Hide file tree
Showing 24 changed files with 186 additions and 50 deletions.
4 changes: 2 additions & 2 deletions packages/infinitegrid/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@
"karma-chrome-launcher": "^2.2.0",
"karma-mocha": "^1.3.0",
"karma-mocha-reporter": "^2.2.5",
"karma-typescript": "^5.5.3",
"karma-typescript": "^5.5.3",
"karma-viewport": "^1.0.4",
"mocha": "^6.0.2",
"postcss-loader": "^4.1.0",
Expand Down Expand Up @@ -122,7 +122,7 @@
"@cfcs/core": "^0.0.5",
"@egjs/children-differ": "^1.0.1",
"@egjs/component": "^3.0.0",
"@egjs/grid": "^1.13.0",
"@egjs/grid": "^1.14.1",
"@egjs/list-differ": "^1.0.0"
}
}
16 changes: 13 additions & 3 deletions packages/infinitegrid/src/GroupManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export interface InfiniteGridGroupStatus {
}

export interface GroupManagerOptions extends GridOptions {
appliedItemChecker?: (item: InfiniteGridItem, grid: Grid) => boolean;
gridConstructor: GridFunction | null;
gridOptions: Record<string, any>;
}
Expand All @@ -43,6 +44,7 @@ export interface GroupManagerStatus {
export class GroupManager extends Grid<GroupManagerOptions> {
public static defaultOptions: Required<GroupManagerOptions> = {
...Grid.defaultOptions,
appliedItemChecker: () => false,
gridConstructor: null,
gridOptions: {},
};
Expand Down Expand Up @@ -207,20 +209,28 @@ export class GroupManager extends Grid<GroupManagerOptions> {
groups.reverse();
}

const appliedItemChecker = this.options.appliedItemChecker;
const groupItems = this.groupItems;
const outlineLength = this.getComputedOutlineLength(groupItems);
const outlineSize = this.getComputedOutlineSize(groupItems);
const itemRenderer = this.itemRenderer;

groups.forEach((group) => {
const grid = group.grid;
const gridItems = grid.getItems();
const gridItems = grid.getItems() as InfiniteGridItem[];
const isVirtual = group.type === GROUP_TYPE.VIRTUAL && !gridItems[0];
const appliedItems = gridItems.filter((item) => item.mountState !== MOUNT_STATE.UNCHECKED && item.rect.width);
let gridOutlines: GridOutlines;

grid.outlineLength = outlineLength;
grid.outlineSize = outlineSize;

const appliedItems = gridItems.filter((item) => {
if (item.mountState === MOUNT_STATE.UNCHECKED || !item.rect.width) {
itemRenderer.updateItem(item, true);
}
return (item.orgRect.width && item.rect.width) || appliedItemChecker(item, grid);
});
let gridOutlines: GridOutlines;

if (isVirtual) {
gridOutlines = this._applyVirtualGrid(grid, direction, nextOutline);
} else if (appliedItems.length) {
Expand Down
2 changes: 1 addition & 1 deletion packages/infinitegrid/src/Infinite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ export class Infinite extends Component<InfiniteEvents> {
endOutline,
} = item;

if (!startOutline.length || !endOutline.length) {
if (!startOutline.length || !endOutline.length || isFlatOutline(startOutline, endOutline)) {
return false;
}
const startPos = Math.min(...startOutline);
Expand Down
5 changes: 4 additions & 1 deletion packages/infinitegrid/src/InfiniteGrid.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Component, { ComponentEvent } from "@egjs/component";
import {
import Grid, {
ContainerManager,
DEFAULT_GRID_OPTIONS,
Properties,
Expand Down Expand Up @@ -91,6 +91,7 @@ class InfiniteGrid<Options extends InfiniteGridOptions = InfiniteGridOptions> ex
threshold: 100,
useRecycle: true,
scrollContainer: null,
appliedItemChecker: (() => false) as (item: InfiniteGridItem, grid: Grid) => boolean,
} as Required<InfiniteGridOptions>;
public static propertyTypes = INFINITEGRID_PROPERTY_TYPES;
protected wrapperElement: HTMLElement;
Expand Down Expand Up @@ -121,6 +122,7 @@ class InfiniteGrid<Options extends InfiniteGridOptions = InfiniteGridOptions> ex
threshold,
useRecycle,
scrollContainer,
appliedItemChecker,
...gridOptions
} = this.options;
// options.container === false, wrapper = container, scrollContainer = document.body
Expand Down Expand Up @@ -176,6 +178,7 @@ class InfiniteGrid<Options extends InfiniteGridOptions = InfiniteGridOptions> ex

infinite.setSize(scrollManager.getContentSize());
const groupManager = new GroupManager(containerElement, {
appliedItemChecker: appliedItemChecker!,
gridConstructor: gridConstructor!,
externalItemRenderer: itemRenderer,
externalContainerManager: containerManager,
Expand Down
1 change: 1 addition & 0 deletions packages/infinitegrid/src/consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export const ITEM_INFO_PROPERTIES: Record<keyof InfiniteGridItemInfo, true> = {
html: true,
data: true,
inserted: true,
attributes: true,
};


Expand Down
5 changes: 5 additions & 0 deletions packages/infinitegrid/src/grids/MasonryInfiniteGrid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,10 @@ export class MasonryInfiniteGrid extends InfiniteGrid<MasonryInfiniteGridOptions
...InfiniteGrid.defaultOptions,
...MasonryGrid.defaultOptions,
gridConstructor: MasonryGrid,
appliedItemChecker: (item, grid) => {
const column = parseFloat(item.attributes.column) || 0;

return column >= grid.outlineLength;
},
} as const;
}
8 changes: 8 additions & 0 deletions packages/infinitegrid/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export interface InfiniteGridItemInfo {
element?: HTMLElement | null;
html?: string;
data?: Record<string, any>;
attributes?: Record<string, any>;
}


Expand Down Expand Up @@ -89,9 +90,16 @@ export interface InfiniteGridOptions extends GridOptions {
* @ko Infinite 기능을 적용할 Grid 클래스.
*/
gridConstructor?: GridFunction;
/**
* A function that checks whether non-rendering items are included in the Grid.
* @ko 렌더링 되지 않는 아이템를 Grid에 포함시킬지 체크하는 함수.
* @private
*/
appliedItemChecker?: (item: InfiniteGridItem, grid: Grid) => boolean;
/**
* class that renders the DOM.
* @ko DOM을 렌더하는 클래스.
* @private
*/
renderer?: Renderer | null;
}
Expand Down
14 changes: 10 additions & 4 deletions packages/infinitegrid/test/unit/InfiniteGrid.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1090,6 +1090,7 @@ describe("test InfiniteGrid", () => {
// Given
const nums = new Array(29).fill(0).map((_, i) => i);

// 0 ~ 9
ig!.syncItems(nums.map((child) => {
return {
groupKey: Math.floor(child / 3),
Expand All @@ -1098,6 +1099,7 @@ describe("test InfiniteGrid", () => {
};
}));

// 0 ~ 8
ig!.setCursors(0, 8);
// all cursors
await waitEvent(ig!, "renderComplete");
Expand All @@ -1106,15 +1108,15 @@ describe("test InfiniteGrid", () => {


ig!.setStatus(ig!.getStatus(STATUS_TYPE.MINIMIZE_INVISIBLE_ITEMS));
// visible(0 ~ 2) invisible(3 ~ 9)
// visible(0 ~ 2) invisible(3 ~ 8) unchecked(9)
await waitEvent(ig!, "renderComplete");

// When
ig!.getScrollContainerElement().scrollTop = 3000;

const requestAppendEvent = await waitEvent<OnRequestAppend>(ig!, "requestAppend");

// 3 ~ 9
// 3 ~ 8
ig!.append(flat(requestAppendEvent.nextGroupKeys.map((groupKey) => {
return [0, 1, 2].map((index) => {
const child = (groupKey as number) * 3 + index;
Expand All @@ -1128,10 +1130,14 @@ describe("test InfiniteGrid", () => {

await waitEvent(ig!, "renderComplete");

const items = ig!.getItems(true);
const items0to26 = items.slice(0, 26);
const items27 = items.slice(27);
// Then
expect(ig!.getStartCursor()).to.be.equals(6);
expect(ig!.getEndCursor()).to.be.equals(9);
expect(ig!.getItems(true).every((item) => item.type !== ITEM_TYPE.VIRTUAL)).to.be.equals(true);
expect(ig!.getEndCursor()).to.be.equals(8);
expect(items0to26.every((item) => item.type !== ITEM_TYPE.VIRTUAL)).to.be.equals(true);
expect(items27.every((item) => item.type === ITEM_TYPE.VIRTUAL)).to.be.equals(true);
});
it(`should check if requestAppend event for invisible items is triggered`, async () => {
// Given
Expand Down
48 changes: 48 additions & 0 deletions packages/infinitegrid/test/unit/MasonryInfiniteGrid.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,5 +103,53 @@ describe("test InfiniteGrid", () => {
expect(ig.getStartCursor()).to.be.equals(3);
expect(ig.getVisibleGroups()[0].grid.getOutlines().start).to.be.lengthOf(2);
});
it("should check whether the outline of the invisible area and the last area are connected", async () => {
// Given
container!.innerHTML = `<div class="wrapper" style="width: 330px; height: 500px;"></div>`;
const wrapper = container!.querySelector<HTMLElement>(".wrapper")!;
ig = new MasonryInfiniteGrid(wrapper, {
container: true,
});

const bottomArea = document.createElement("div");

bottomArea.style.cssText = "position: relative;height: 500px";
wrapper.appendChild(bottomArea);

ig!.syncItems([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13].map((child) => {
// 0 ~ 3, 4 ~ 7, 8 ~ 11, 12 ~ 13
const width = child >= 12 ? "100%" : "150px";
const column = child >= 12 ? "2" : "";

return {
groupKey: Math.floor(child / 4),
key: `key${child}`,
attributes: {
column,
},
html: `<div style="position:absolute; width: ${width}; height: 250px">${child}</div>`,
};
}));

ig!.renderItems();

// [0, 0]
await waitEvent(ig!, "renderComplete");

// [0, 1]
await waitEvent(ig!, "renderComplete");


// 12 left 0, top 1000
const rect12 = ig.getItems()[12].cssRect;
// 13 left 0, top 1000
const rect13 = ig.getItems()[13].cssRect;

// Then
expect(rect12.left).to.be.equals(0);
expect(rect12.top).to.be.equals(1000);
expect(rect13.left).to.be.equals(0);
expect(rect13.top).to.be.equals(1000);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {
} from '@egjs/infinitegrid';
import { NgxInfiniteGridInterface } from './ngx-infinitegrid.interface';
import { NgxInfiniteGridProps } from './types';
import Grid, { GridOptions } from '@egjs/grid';

@Component({
selector: 'ngx-infinite-grid, [NgxInfiniteGrid]',
Expand Down Expand Up @@ -80,6 +81,7 @@ export class NgxInfiniteGridComponent
@Input() useResizeObserver!: NgxInfiniteGridProps['useResizeObserver'];
@Input() observeChildren!: NgxInfiniteGridProps['observeChildren'];
@Input() scrollContainer!: NgxInfiniteGridProps['scrollContainer'];
@Input() appliedItemChecker!: NgxInfiniteGridProps['appliedItemChecker'];

@Input() usePlaceholder!: NgxInfiniteGridProps['useFirstRender'];
@Input() useLoading!: NgxInfiniteGridProps['useLoading'];
Expand All @@ -88,6 +90,7 @@ export class NgxInfiniteGridComponent
@Input() items: NgxInfiniteGridProps['items'] = [];
@Input() trackBy: NgxInfiniteGridProps['trackBy'] = ((_, item) => item.key);
@Input() groupBy: NgxInfiniteGridProps['groupBy'] = ((_, item) => item.groupKey);
@Input() infoBy: NgxInfiniteGridProps['infoBy'] = () => ({});
@Output() renderComplete!: EventEmitter<OnRenderComplete>;
@Output() contentError!: EventEmitter<OnContentError>;
@Output() changeScroll!: EventEmitter<OnChangeScroll>;
Expand Down Expand Up @@ -213,12 +216,21 @@ export class NgxInfiniteGridComponent
const items = this.items;
const trackBy = this.trackBy;
const groupBy = this.groupBy;
const infoBy = this.infoBy;

return items.map((item, i) => {
const {
data,
...rest
} = infoBy(i, item);
return {
groupKey: groupBy(i, item),
key: trackBy(i, item),
data: item,
...rest,
data: {
...data,
...item,
},
};
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ export interface NgxInfiniteGridProps extends NgxInfiniteGridEvents, Required<In
items: any[];
trackBy: (index: number, item: any) => any;
groupBy: (index: number, item: any) => any;
infoBy: (index: number, item: any) => Record<string, any>;
}
13 changes: 12 additions & 1 deletion packages/react-infinitegrid/src/InfiniteGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import * as React from "react";
import VanillaInfiniteGrid, {
InfiniteGridOptions, InfiniteGridFunction,
Renderer,
InfiniteGridItemInfo, ITEM_TYPE,
InfiniteGridItemInfo,
ITEM_TYPE,
InfiniteGridMethods,
withInfiniteGridMethods,
getRenderingItems,
Expand Down Expand Up @@ -114,12 +115,22 @@ export abstract class InfiniteGrid<T extends InfiniteGridOptions>
const attributePrefix = props.attributePrefix || VanillaInfiniteGrid.defaultOptions.attributePrefix;
const itemBy = props.itemBy || ((item: React.ReactElement) => item.key);
const groupBy = props.groupBy || ((item: React.ReactElement) => item.props[`${attributePrefix}groupkey`]);
const infoBy = props.infoBy || (() => ({}));


return children.map((child, i) => {
const {
data,
...rest
} = infoBy(child, i) || {};


return {
groupKey: groupBy(child, i),
key: itemBy(child, i),
...rest,
data: {
...data,
jsx: child,
},
};
Expand Down
1 change: 1 addition & 0 deletions packages/react-infinitegrid/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ export interface ReactInfiniteGridProps extends ReactInfiniteGridEvents {
useFirstRender?: boolean;
itemBy?: (item: React.ReactElement, index: number) => string | number;
groupBy?: (item: React.ReactElement, index: number) => string | number;
infoBy?: (item: React.ReactElement, index: number) => Record<string, any>;
}
11 changes: 10 additions & 1 deletion packages/svelte-infinitegrid/src/InfiniteGrid.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,21 @@
const items = $$props.items || [];
const itemBy = $$props.itemBy || ((item) => item.key);
const groupBy = $$props.groupBy || ((item) => item.groupKey);
const infoBy = $$props.infoBy || (() => ({}));
return items.map((item, i) => {
const {
data,
...rest
} = infoBy(child, i) || {};
return {
groupKey: groupBy(item, i),
key: itemBy(item, i),
data: item,
...rest,
data: {
...data,
...item,
},
};
});
}
Expand Down
3 changes: 3 additions & 0 deletions packages/svelte-infinitegrid/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ export interface SveltInfiniteGridOptions {
usePlaceholder?: boolean;
useLoading?: boolean;
status?: InfiniteGridStatus;
itemBy?: (item: any, index: number) => string | number;
groupBy?: (item: any, index: number) => string | number;
infoBy?: (item: any, index: number) => Record<string, any>;
}

export default abstract class InfiniteGrid<T extends InfiniteGridOptions> extends SvelteComponentDev {
Expand Down

0 comments on commit 6fd5c0b

Please sign in to comment.