Skip to content

Commit

Permalink
feat: add isReachStart, isReachEnd props and reacthStart, reachEnd props
Browse files Browse the repository at this point in the history
  • Loading branch information
daybrush committed Aug 21, 2024
1 parent 3bf563b commit a577cf0
Show file tree
Hide file tree
Showing 6 changed files with 194 additions and 23 deletions.
39 changes: 36 additions & 3 deletions packages/infinitegrid/src/Infinite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ export interface InfiniteOptions {
useRecycle?: boolean;
threshold?: number;
defaultDirection?: "start" | "end";
isReachStart?: boolean;
isReachEnd?: boolean;
}

export interface InfiniteItemPart {
Expand Down Expand Up @@ -62,9 +64,17 @@ export class Infinite extends Component<InfiniteEvents> {
threshold: 0,
useRecycle: true,
defaultDirection: "end",
isReachStart: false,
isReachEnd: false,
...options,
};
}
public set isReachStart(value: boolean) {
this.options.isReachStart = value;
}
public set isReachEnd(value: boolean) {
this.options.isReachEnd = value;
}
public scroll(scrollPos: number) {
const prevStartCursor = this.startCursor;
const prevEndCursor = this.endCursor;
Expand All @@ -75,11 +85,34 @@ export class Infinite extends Component<InfiniteEvents> {
defaultDirection,
threshold,
useRecycle,
isReachEnd,
isReachStart,
} = this.options;
const isDirectionEnd = defaultDirection === "end";

if (!length) {
this.trigger(isDirectionEnd ? "requestAppend" : "requestPrepend", {
if (isReachStart && isReachEnd) {
return;
}
let requestType: "requestAppend" | "requestPrepend" | "" = "";

if (!isReachEnd && isDirectionEnd) {
// 1st order
requestType = "requestAppend";
} else if (!isReachStart && !isDirectionEnd) {
// 2nd order
requestType = "requestPrepend";
} else if (!isReachEnd && isReachStart) {
// 3rd order
requestType = "requestAppend";
} else if (isReachEnd && !isReachStart) {
// 4th order
requestType = "requestPrepend";
}
if (!requestType) {
return;
}
this.trigger(requestType, {
key: undefined,
isVirtual: false,
});
Expand Down Expand Up @@ -211,12 +244,12 @@ export class Infinite extends Component<InfiniteEvents> {
}
}
} else if (!this._requestVirtualItems()) {
if ((!isDirectionEnd || !isEnd) && isStart) {
if ((!isDirectionEnd || !isEnd || isReachEnd) && isStart && !isReachStart) {
this.trigger("requestPrepend", {
key: items[prevStartCursor].key,
isVirtual: false,
});
} else if ((isDirectionEnd || !isStart) && isEnd) {
} else if ((isDirectionEnd || !isStart || isReachStart) && isEnd && !isReachEnd) {
this.trigger("requestAppend", {
key: items[prevEndCursor].key,
isVirtual: false,
Expand Down
47 changes: 43 additions & 4 deletions packages/infinitegrid/src/InfiniteGrid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Grid, {
GridItem,
ResizeWatcherResizeEvent,
getUpdatedItems,
PROPERTY_TYPE,
} from "@egjs/grid";
import {
DIRECTION,
Expand Down Expand Up @@ -94,8 +95,14 @@ class InfiniteGrid<Options extends InfiniteGridOptions = InfiniteGridOptions> ex
threshold: 100,
useRecycle: true,
scrollContainer: null,
isReachStart: false,
isReachEnd: false,
appliedItemChecker: (() => false) as (item: InfiniteGridItem, grid: Grid) => boolean,
} as Required<InfiniteGridOptions>;
public static infinitegridTypes = {
isReachEnd: PROPERTY_TYPE.PROPERTY,
isReachStart: PROPERTY_TYPE.PROPERTY,
};
public static propertyTypes = INFINITEGRID_PROPERTY_TYPES;
protected wrapperElement: HTMLElement;
protected scrollManager: ScrollManager;
Expand Down Expand Up @@ -394,7 +401,6 @@ class InfiniteGrid<Options extends InfiniteGridOptions = InfiniteGridOptions> ex
scrollManager: this.scrollManager.getStatus(),
};
}

/**
* You can set placeholders to restore status or wait for items to be added.
* @ko status 복구 또는 아이템 추가 대기를 위한 placeholder를 설정할 수 있다.
Expand Down Expand Up @@ -622,6 +628,16 @@ class InfiniteGrid<Options extends InfiniteGridOptions = InfiniteGridOptions> ex
public isWait() {
return !!this._waitType;
}
/**
* <ko>scrollOffset(startOffset) 또는 scrollSize의 사이즈를 수동으로 업데이트 한다. 변경이 됐다면 스크롤이 발생시킨다.</ko>
*/
public resizeScroll() {
const result = this._resizeScroll();

if (result) {
this._scroll();
}
}
/**
* Releases the instnace and events and returns the CSS of the container and elements.
* @ko 인스턴스와 이벤트를 해제하고 컨테이너와 엘리먼트들의 CSS를 되돌린다.
Expand All @@ -647,6 +663,14 @@ class InfiniteGrid<Options extends InfiniteGridOptions = InfiniteGridOptions> ex
};
});
}
private _setIsReachStart(value: boolean) {
this.options.isReachStart = value;
this.infinite.isReachStart = value;
}
private _setIsReachEnd(value: boolean) {
this.options.isReachEnd = value;
this.infinite.isReachEnd = value;
}
private _syncItems(state?: Record<string, any>): void {
this._getRenderer().syncItems(this._getRendererItems(), state);
}
Expand All @@ -659,9 +683,10 @@ class InfiniteGrid<Options extends InfiniteGridOptions = InfiniteGridOptions> ex
private _resizeScroll() {
const scrollManager = this.scrollManager;

scrollManager.resize();

const result = scrollManager.resize();
this.infinite.setSize(scrollManager.getContentSize());

return result;
}
private _syncGroups(isUpdate?: boolean) {
const infinite = this.infinite;
Expand Down Expand Up @@ -846,6 +871,14 @@ class InfiniteGrid<Options extends InfiniteGridOptions = InfiniteGridOptions> ex
nextGroupKey: e.nextKey,
nextGroupKeys: e.nextKeys || [],
isVirtual: e.isVirtual,
reachStart: () => {
this._setIsReachStart(true);
this._scroll();
},
reachEnd: () => {
this._setIsReachEnd(true);
this._scroll();
},
wait: () => {
this.wait(direction);
},
Expand Down Expand Up @@ -1019,6 +1052,12 @@ class InfiniteGrid<Options extends InfiniteGridOptions = InfiniteGridOptions> ex
}
}

interface InfiniteGrid extends Properties<typeof InfiniteGrid> { }
interface InfiniteGrid extends Properties<typeof InfiniteGrid> {
isReachStart: boolean;
isReachEnd: boolean;
}

export default InfiniteGrid;



8 changes: 8 additions & 0 deletions packages/infinitegrid/src/ScrollManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ export class ScrollManager extends Component<ScrollManagerEvents> {
eventTarget.scrollTop += y;
}
}
/**
* @return Returns true if scrollOffset or contentSize has changed, otherwise returns false. <ko>scrollOffset 또는 contentSize가 변화가 있으면 true 아니면 false를 반환한다.</ko>
*/
public resize() {
const scrollContainer = this.scrollContainer;
const horizontal = this.options.horizontal;
Expand All @@ -139,6 +142,9 @@ export class ScrollManager extends Component<ScrollManagerEvents> {
: scrollContainer.getBoundingClientRect();
const containerRect = this.container.getBoundingClientRect();

const prevScrollOffset = this.scrollOffset;
const prevContentSize = this.contentSize;

this.scrollOffset = (this.getOrgScrollPos()! || 0) + (horizontal
? containerRect.left - scrollContainerRect.left
: containerRect.top - scrollContainerRect.top);
Expand All @@ -148,6 +154,8 @@ export class ScrollManager extends Component<ScrollManagerEvents> {
} else {
this.contentSize = horizontal ? scrollContainer.offsetWidth : scrollContainer.offsetHeight;
}

return prevScrollOffset !== this.scrollOffset || prevContentSize !== this.contentSize;
}
public destroy() {
const container = this.container;
Expand Down
1 change: 0 additions & 1 deletion packages/infinitegrid/src/consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ export const IGNORE_PROPERITES_MAP = {
autoResize: true,
} as const;


export const INFINITEGRID_PROPERTY_TYPES = {
...GRID_PROPERTY_TYPES,
};
Expand Down
94 changes: 80 additions & 14 deletions packages/infinitegrid/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,15 @@ export interface InfiniteGridOptions extends GridOptions {
* @default true
*/
useRecycle?: boolean;
/**
* @default false
*/
isReachStart?: boolean;
/**
* @default false
*/
isReachEnd?: boolean;

/**
* You can set the scrollContainer directly. In this case, the container becomes the wrapper itself.
* @ko scrollContainer를 직접 정할 수 있다. 이 경우 container는 wrapper 자기 자신이 된다.
Expand Down Expand Up @@ -119,41 +128,98 @@ export interface InsertedPlaceholdersResult {

/**
* @typedef
* @property - An InfiniteGrid instance that triggered this event. <ko>이 이벤트를 트리거한 InfiniteGrid의 인스턴스</ko>
* @property - Last group key. <ko>마지막 그룹의 키.</ko>
* @property - The key of the next group that should replace Virtual Item(placeholder)s. <ko>Virtual Item(placeholder)들을 대체해야 할 다음 그룹의 키.</ko>
* @property - Array of the following group keys that need to be replaced with Virtual Item(placeholder)s. <ko>Virtual Item(placeholder)들을 대체해야 할 다음 그룹키 배열.</ko>
* @property - Whether to request virtual groups corresponding to Virtual Item(placeholder)s. <ko>Virtual Item(placeholder)들에 해당하는 가상의 그룹을 요청하는지 여부</ko>
* @property - Set to standby to request data. <ko>데이터를 요청하기 위해 대기 상태로 설정한다.</ko>
* @property - When the data request is complete, it is set to ready state. <ko>데이터 요청이 끝났다면 준비 상태로 설정한다.</ko>
*/
export interface OnRequestAppend {
/**
* An InfiniteGrid instance that triggered this event. <ko>이 이벤트를 트리거한 InfiniteGrid의 인스턴스</ko>
*/
currentTarget: InfiniteGrid;
/**
* Last group key. <ko>마지막 그룹의 키.</ko>
*/
groupKey: string | number | undefined;
/**
* The key of the next group that should replace Virtual Item(placeholder)s. <ko>Virtual Item(placeholder)들을 대체해야 할 다음 그룹의 키.</ko>
*/
nextGroupKey?: string | number | undefined;
/**
* Array of the following group keys that need to be replaced with Virtual Item(placeholder)s.
* <ko>Virtual Item(placeholder)들을 대체해야 할 다음 그룹키 배열.</ko>
*/
nextGroupKeys: Array<string | number>;
/**
* Whether to request virtual groups corresponding to Virtual Item(placeholder)s.
* <ko>Virtual Item(placeholder)들에 해당하는 가상의 그룹을 요청하는지 여부</ko>
*/
isVirtual: boolean;
/**
* Call this when the end has been reached and there are no more groups (or items) to add. Or set the `isReachEnd` prop to true.
* <ko>끝에 도달해서 더 이상 추가할 그룹(또는 아이템)이 없는 경우 호출해라. 또는 `isReachEnd` 옵션을 true로 설정해라.</ko>
*/
reachEnd(): void;
/**
* Call this when the start has been reached and there are no more groups (or items) to add. Or set the `isReachStart` prop to true.
* <ko>시작에 도달해서 더 이상 추가할 그룹(또는 아이템)이 없는 경우 호출해라. 또는 `isReachStart` 옵션을 true로 설정해라.</ko>
*/
reachStart(): void;
/**
* Set to standby to request data. <ko>데이터를 요청하기 위해 대기 상태로 설정한다.</ko>
*/
wait(): void;
/**
* When the data request is complete, it is set to ready state. <ko>데이터 요청이 끝났다면 준비 상태로 설정한다.</ko>
*/
ready(): void;
}

/**
* @typedef
* @property - An InfiniteGrid instance that triggered this event. <ko>이 이벤트를 트리거한 InfiniteGrid의 인스턴스</ko>
* @property - First group key. <ko>첫번째 그룹의 키.</ko>
* @property - The key of the next group that should replace Virtual Item(placeholder)s. <ko>Virtual Item(placeholder)들을 대체해야 할 다음 그룹의 키.</ko>
* @property - Array of the following group keys that need to be replaced with Virtual Item(placeholder)s. <ko>Virtual Item(placeholder)들을 대체해야 할 다음 그룹키 배열.</ko>
* @property - Whether to request virtual groups corresponding to Virtual Item(placeholder)s. <ko>Virtual Item(placeholder)들에 해당하는 가상의 그룹을 요청하는지 여부</ko>
* @property - Set to standby to request data. <ko>데이터를 요청하기 위해 대기 상태로 설정한다.</ko>
* @property - When the data request is complete, it is set to ready state. <ko>데이터 요청이 끝났다면 준비 상태로 설정한다.</ko>
*/
export interface OnRequestPrepend {
/**
* An InfiniteGrid instance that triggered this event.
* <ko>이 이벤트를 트리거한 InfiniteGrid의 인스턴스</ko>
*/
currentTarget: InfiniteGrid;
/**
* The key of the next group that should replace Virtual Item(placeholder)s.
* <ko>Virtual Item(placeholder)들을 대체해야 할 다음 그룹의 키.</ko>
*/
groupKey: string | number | undefined;
/**
* The key of the next group that should replace Virtual Item(placeholder)s.
* <ko>Virtual Item(placeholder)들을 대체해야 할 다음 그룹의 키.</ko>
*/
nextGroupKey?: string | number | undefined;
/**
* Array of the following group keys that need to be replaced with Virtual Item(placeholder)s.
* <ko>Virtual Item(placeholder)들을 대체해야 할 다음 그룹키 배열.</ko>
*/
nextGroupKeys: Array<string | number>;
/**
* Whether to request virtual groups corresponding to Virtual Item(placeholder)s.
* <ko>Virtual Item(placeholder)들에 해당하는 가상의 그룹을 요청하는지 여부</ko>
*/
isVirtual: boolean;
/**
* Call this when the end has been reached and there are no more groups (or items) to add. Or set the `isReachEnd` prop to true.
* <ko>끝에 도달해서 더 이상 추가할 그룹(또는 아이템)이 없는 경우 호출해라. 또는 `isReachEnd` 옵션을 true로 설정해라.</ko>
*/
reachEnd(): void;
/**
* Call this when the start has been reached and there are no more groups (or items) to add. Or set the `isReachStart` prop to true.
* <ko>시작에 도달해서 더 이상 추가할 그룹(또는 아이템)이 없는 경우 호출해라. 또는 `isReachStart` 옵션을 true로 설정해라.</ko>
*/
reachStart(): void;
/**
* Set to standby to request data.
* <ko>데이터를 요청하기 위해 대기 상태로 설정한다.</ko>
*/
wait(): void;
/**
* When the data request is complete, it is set to ready state.
* <ko>데이터 요청이 끝났다면 준비 상태로 설정한다.</ko>
*/
ready(): void;
}

Expand Down
28 changes: 27 additions & 1 deletion packages/infinitegrid/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { withClassMethods } from "@cfcs/core";
import { camelize, withClassMethods } from "@cfcs/core";
import Grid, { GRID_PROPERTY_TYPES } from "@egjs/grid";
import { diff } from "@egjs/list-differ";
import { GROUP_TYPE, IGNORE_PROPERITES_MAP, INFINITEGRID_METHODS, ITEM_INFO_PROPERTIES, ITEM_TYPE } from "./consts";
Expand Down Expand Up @@ -287,11 +287,37 @@ export function getRenderingItems(items: InfiniteGridItemInfo[], options: Render
export function InfiniteGridGetterSetter(component: {
prototype: InfiniteGrid<any>,
propertyTypes: typeof GRID_PROPERTY_TYPES,
infinitegridTypes: any,
}) {
const {
prototype,
propertyTypes,
infinitegridTypes,
} = component;

for (const name in infinitegridTypes) {
const attributes: Record<string, any> = {
enumerable: true,
configurable: true,
get: function get(this: InfiniteGrid) {
const options = this.options;

return options[name];
},
set: function set(this: InfiniteGrid, value: any) {
const setterName = `_${camelize(`set ${name}`)}`;

if (this[setterName]) {
this[setterName](value);
} else {
this.options[name] = value;
}
},
};


Object.defineProperty(prototype, name, attributes);
}
for (const name in propertyTypes) {
const attributes: Record<string, any> = {
enumerable: true,
Expand Down

0 comments on commit a577cf0

Please sign in to comment.