import Bind from "@web-atoms/core/dist/core/Bind";
import { CancelToken } from "@web-atoms/core/dist/core/types";
import XNode from "@web-atoms/core/dist/core/XNode";
import styled from "@web-atoms/core/dist/style/styled";
import { AtomControl } from "@web-atoms/core/dist/web/controls/AtomControl";
import AtomRepeater from "@web-atoms/web-controls/dist/basic/AtomRepeater";
const loadMoreSet = Symbol("loadMoreSet");
styled.css `
margin: 10px;
padding: 10px;
& > span {
background-color: lightgray;
border-radius: 10px;
padding: 3px;
padding-left: 10px;
padding-right: 10px;
border: solid 1px gray;
}
`.installGlobal("[data-load-more=load-more]");
export interface IAnyPagedItems {
items: any[];
total: number;
}
export interface IInfiniteRepeater extends AtomRepeater {
pagedItems: IAnyPagedItems;
[loadMoreSet]: CancelToken;
start: number;
}
const pagedItemsSetter = AtomControl.registerProperty("paged-items", "paged-items",
(control: IInfiniteRepeater, element, value) => {
if (value && value.items) {
let cancelToken = control[loadMoreSet];
control.footerRenderer ??= () =>
;
control.headerRenderer ??= () => ;
if (!cancelToken) {
control[loadMoreSet] = cancelToken = new CancelToken();
control.bindEvent(control.element, "loadMoreItems", (e: any) => {
const ce = new CustomEvent("moreItems", {
detail: {
pagedItems: control.pagedItems,
cancelToken
},
bubbles: false
});
control.element.dispatchEvent(ce);
});
} else {
cancelToken.cancel();
control[loadMoreSet] = cancelToken = new CancelToken();
}
const items = control.items;
if (items && Array.isArray(items)) {
items.clear();
items.addAll(value.items);
} else {
control.items = value.items;
}
setTimeout(() => {
const ce = control.element?.firstElementChild as HTMLElement;
ce?.scrollIntoView();
}, 100);
control.footer = value.total && value.items && value.items.length < value.total;
(control as any).pagedItems = value;
}
});
export type RepeaterLoader = (start: number) => (control: AtomControl, element: HTMLElement, cancelToken: CancelToken) => any;
const scrollToBottom = ({ target, detail: { type, index}}) => {
if (!(type === "add" && index === 0) && type !== "reset") {
return;
}
setTimeout(() => {
const e = target.firstElementChild as HTMLElement;
console.log(e);
e?.scrollIntoView(true);
}, 1);
};
export default class InfiniteRepeater {
public static pagedItems = (start: RepeaterLoader) => {
const setter = start(0);
const setters = pagedItemsSetter(Bind.oneWayAsync(setter)) as any;
setters["event-more-items"] = Bind.event(async (s: any, e) => {
const st = s.items?.length ?? 0;
if (!st) {
return;
}
const cancelToken = s[loadMoreSet];
const loader = start(st);
const results = await loader(s, e.target as any, cancelToken);
s.items.addAll(results.items);
s.footer = results.items.length > 0;
});
// setters["event-items-updated"] = scrollToBottom;
return setters;
};
}