Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add infoBy prop for frameworks #538

Merged
merged 8 commits into from
May 26, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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.0-beta.2",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might have to fix this to 1.14.0 after release.

"@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;
}
6 changes: 6 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,6 +90,11 @@ export interface InfiniteGridOptions extends GridOptions {
* @ko Infinite 기능을 적용할 Grid 클래스.
*/
gridConstructor?: GridFunction;
/**
* Grid class to apply Infinite function.
* @ko Infinite 기능을 적용할 Grid 클래스.
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Descriptions are misused.

appliedItemChecker?: (item: InfiniteGridItem, grid: Grid) => boolean;
/**
* class that renders the DOM.
* @ko DOM을 렌더하는 클래스.
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 @@ -164,8 +167,10 @@ export class NgxInfiniteGridComponent
fromEvent(this._renderer, 'requestUpdate')
.pipe(takeUntil(this._destroy$))
.subscribe(() => {
this._isChange = true;
this._updateVisibleChildren();
this._ngZone.run(() => {
this._isChange = true;
this._updateVisibleChildren();
});
});

mountRenderingItems(this._getItemInfos(), {
Expand Down Expand Up @@ -211,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