Skip to content

Commit c0028e5

Browse files
authored
fix(pagination): correctly render fixedItems with low page count (#464)
1 parent fdfa104 commit c0028e5

File tree

2 files changed

+103
-84
lines changed

2 files changed

+103
-84
lines changed
Lines changed: 102 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,4 @@
1-
import {
2-
For,
3-
Show,
4-
batch,
5-
createEffect,
6-
createSignal,
7-
untrack,
8-
} from "solid-js";
1+
import { For, Show, createMemo } from "solid-js";
92

103
import { usePaginationContext } from "./pagination-context";
114

@@ -14,86 +7,112 @@ export interface PaginationItemsProps {}
147
export function PaginationItems(props: PaginationItemsProps) {
158
const context = usePaginationContext();
169

17-
const [showFirst, setShowFirst] = createSignal(false);
18-
const [showLast, setShowLast] = createSignal(false);
19-
20-
const [showFirstEllipsis, setShowFirstEllipsis] = createSignal(false);
21-
const [showLastEllipsis, setShowLastEllipsis] = createSignal(false);
22-
23-
const [previousSiblingCount, setPreviousSiblingCount] = createSignal(0);
24-
const [nextSiblingCount, setNextSiblingCount] = createSignal(0);
25-
26-
createEffect(() => {
27-
batch(() => {
28-
setShowFirst(
29-
context.showFirst() && context.page() - 1 > context.siblingCount(),
30-
);
31-
setShowLast(
32-
context.showLast() &&
33-
context.count() - context.page() > context.siblingCount(),
34-
);
35-
36-
setShowFirstEllipsis(
37-
context.page() - (context.showFirst() ? 2 : 1) > context.siblingCount(),
38-
);
39-
setShowLastEllipsis(
40-
context.count() - context.page() - (context.showLast() ? 1 : 0) >
41-
context.siblingCount(),
42-
);
43-
44-
setPreviousSiblingCount(
45-
Math.min(context.page() - 1, context.siblingCount()),
46-
);
47-
setNextSiblingCount(
48-
Math.min(context.count() - context.page(), context.siblingCount()),
49-
);
50-
51-
if (context.fixedItems() !== false) {
52-
// Untrack to avoid recursion
53-
untrack(() => {
54-
// Add back the difference between the opposite side and the sibling count
55-
setPreviousSiblingCount(
56-
(prev) =>
57-
prev + Math.max(context.siblingCount() - nextSiblingCount(), 0),
58-
);
59-
setNextSiblingCount(
60-
(prev) =>
61-
prev +
62-
Math.max(context.siblingCount() - previousSiblingCount(), 0),
63-
);
64-
});
65-
66-
if (!showFirst()) setNextSiblingCount((prev) => prev + 1);
67-
if (!showLast()) setPreviousSiblingCount((prev) => prev + 1);
68-
69-
// Check specifically if true and not "no-ellipsis"
70-
if (context.fixedItems() === true) {
71-
if (!showFirstEllipsis()) setNextSiblingCount((prev) => prev + 1);
72-
if (!showLastEllipsis()) setPreviousSiblingCount((prev) => prev + 1);
73-
}
10+
const items = createMemo(() => {
11+
const { count, siblingCount, page, fixedItems, showFirst, showLast } =
12+
context;
13+
// render directly if count is so small that it does not make sense to render an ellipsis
14+
// this is the case for if count is lower than 2x siblings + 6 for fixedItems and +4 if not fixed items
15+
const renderItemsDirectly =
16+
count() < 2 * siblingCount() + (fixedItems() ? 6 : 4);
17+
18+
//skip the rest of the computation if we can render directly
19+
if (renderItemsDirectly)
20+
return {
21+
renderItemsDirectly,
22+
};
23+
24+
const _showFirst = showFirst() && page() - 1 > siblingCount();
25+
const _showLast = showLast() && count() - page() > siblingCount();
26+
27+
let showFirstEllipsis = page() - (showFirst() ? 2 : 1) > siblingCount();
28+
let showLastEllipsis =
29+
count() - page() - (showLast() ? 1 : 0) > siblingCount();
30+
31+
let previousSiblingCount = Math.min(page() - 1, siblingCount());
32+
let nextSiblingCount = Math.min(count() - page(), siblingCount());
33+
34+
if (fixedItems() !== false) {
35+
// ref to avoid wrong corretions
36+
const previousSiblingCountRef = previousSiblingCount;
37+
const nextSiblingCountRef = nextSiblingCount;
38+
39+
// Add back the difference between the opposite side and the sibling count
40+
previousSiblingCount += Math.max(siblingCount() - nextSiblingCountRef, 0);
41+
nextSiblingCount += Math.max(siblingCount() - previousSiblingCountRef, 0);
42+
43+
if (!_showFirst) nextSiblingCount++;
44+
if (!_showLast) previousSiblingCount++;
45+
46+
// Check specifically if true and not "no-ellipsis"
47+
if (fixedItems() === true) {
48+
if (!showFirstEllipsis) nextSiblingCount++;
49+
if (!showLastEllipsis) previousSiblingCount++;
50+
}
51+
52+
//replace ellipsis if it would replace only one item
53+
if (page() - previousSiblingCount - (showFirst() ? 2 : 1) === 1) {
54+
showFirstEllipsis = false;
55+
previousSiblingCount++;
7456
}
75-
});
57+
if (count() - page() - nextSiblingCount - (showLast() ? 1 : 0) === 1) {
58+
showLastEllipsis = false;
59+
nextSiblingCount++;
60+
}
61+
}
62+
63+
return {
64+
showFirst: _showFirst,
65+
showLast: _showLast,
66+
showFirstEllipsis,
67+
showLastEllipsis,
68+
previousSiblingCount,
69+
nextSiblingCount,
70+
renderItemsDirectly,
71+
};
7672
});
7773

7874
return (
7975
<>
80-
<Show when={showFirst()}>{context.renderItem(1)}</Show>
81-
82-
<Show when={showFirstEllipsis()}>{context.renderEllipsis()}</Show>
83-
84-
<For each={[...Array(previousSiblingCount()).keys()].reverse()}>
85-
{(offset) => <>{context.renderItem(context.page() - (offset + 1))}</>}
86-
</For>
87-
88-
{context.renderItem(context.page())}
89-
90-
<For each={[...Array(nextSiblingCount()).keys()]}>
91-
{(offset) => <>{context.renderItem(context.page() + (offset + 1))}</>}
92-
</For>
93-
94-
<Show when={showLastEllipsis()}>{context.renderEllipsis()}</Show>
95-
96-
<Show when={showLast()}>{context.renderItem(context.count())}</Show>
76+
<Show
77+
when={items().renderItemsDirectly}
78+
fallback={
79+
<>
80+
<Show when={items().showFirst}>{context.renderItem(1)}</Show>
81+
82+
<Show when={items().showFirstEllipsis}>
83+
{context.renderEllipsis()}
84+
</Show>
85+
86+
<For
87+
each={[...Array(items().previousSiblingCount).keys()].reverse()}
88+
>
89+
{(offset) => (
90+
<>{context.renderItem(context.page() - (offset + 1))}</>
91+
)}
92+
</For>
93+
94+
{context.renderItem(context.page())}
95+
96+
<For each={[...Array(items().nextSiblingCount).keys()]}>
97+
{(offset) => (
98+
<>{context.renderItem(context.page() + (offset + 1))}</>
99+
)}
100+
</For>
101+
102+
<Show when={items().showLastEllipsis}>
103+
{context.renderEllipsis()}
104+
</Show>
105+
106+
<Show when={items().showLast}>
107+
{context.renderItem(context.count())}
108+
</Show>
109+
</>
110+
}
111+
>
112+
<For each={[...Array(context.count()).keys()]}>
113+
{(page) => <>{context.renderItem(page + 1)}</>}
114+
</For>
115+
</Show>
97116
</>
98117
);
99118
}

packages/core/src/pagination/pagination-root.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ export function PaginationRoot<T extends ValidComponent = "nav">(
121121
isDisabled: () => local.disabled ?? false,
122122
renderItem: (page) => local.itemComponent({ page }),
123123
renderEllipsis: local.ellipsisComponent,
124-
page: state[0] as Accessor<number>,
124+
page: () => Math.min(state[0]() ?? 1, local.count),
125125
setPage: state[1] as Setter<number>,
126126
};
127127

0 commit comments

Comments
 (0)