Skip to content

Commit

Permalink
fix(pagination): correctly render fixedItems with low page count (#464)
Browse files Browse the repository at this point in the history
  • Loading branch information
madaxen86 authored Aug 21, 2024
1 parent fdfa104 commit c0028e5
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 84 deletions.
185 changes: 102 additions & 83 deletions packages/core/src/pagination/pagination-items.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
import {
For,
Show,
batch,
createEffect,
createSignal,
untrack,
} from "solid-js";
import { For, Show, createMemo } from "solid-js";

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

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

const [showFirst, setShowFirst] = createSignal(false);
const [showLast, setShowLast] = createSignal(false);

const [showFirstEllipsis, setShowFirstEllipsis] = createSignal(false);
const [showLastEllipsis, setShowLastEllipsis] = createSignal(false);

const [previousSiblingCount, setPreviousSiblingCount] = createSignal(0);
const [nextSiblingCount, setNextSiblingCount] = createSignal(0);

createEffect(() => {
batch(() => {
setShowFirst(
context.showFirst() && context.page() - 1 > context.siblingCount(),
);
setShowLast(
context.showLast() &&
context.count() - context.page() > context.siblingCount(),
);

setShowFirstEllipsis(
context.page() - (context.showFirst() ? 2 : 1) > context.siblingCount(),
);
setShowLastEllipsis(
context.count() - context.page() - (context.showLast() ? 1 : 0) >
context.siblingCount(),
);

setPreviousSiblingCount(
Math.min(context.page() - 1, context.siblingCount()),
);
setNextSiblingCount(
Math.min(context.count() - context.page(), context.siblingCount()),
);

if (context.fixedItems() !== false) {
// Untrack to avoid recursion
untrack(() => {
// Add back the difference between the opposite side and the sibling count
setPreviousSiblingCount(
(prev) =>
prev + Math.max(context.siblingCount() - nextSiblingCount(), 0),
);
setNextSiblingCount(
(prev) =>
prev +
Math.max(context.siblingCount() - previousSiblingCount(), 0),
);
});

if (!showFirst()) setNextSiblingCount((prev) => prev + 1);
if (!showLast()) setPreviousSiblingCount((prev) => prev + 1);

// Check specifically if true and not "no-ellipsis"
if (context.fixedItems() === true) {
if (!showFirstEllipsis()) setNextSiblingCount((prev) => prev + 1);
if (!showLastEllipsis()) setPreviousSiblingCount((prev) => prev + 1);
}
const items = createMemo(() => {
const { count, siblingCount, page, fixedItems, showFirst, showLast } =
context;
// render directly if count is so small that it does not make sense to render an ellipsis
// this is the case for if count is lower than 2x siblings + 6 for fixedItems and +4 if not fixed items
const renderItemsDirectly =
count() < 2 * siblingCount() + (fixedItems() ? 6 : 4);

//skip the rest of the computation if we can render directly
if (renderItemsDirectly)
return {
renderItemsDirectly,
};

const _showFirst = showFirst() && page() - 1 > siblingCount();
const _showLast = showLast() && count() - page() > siblingCount();

let showFirstEllipsis = page() - (showFirst() ? 2 : 1) > siblingCount();
let showLastEllipsis =
count() - page() - (showLast() ? 1 : 0) > siblingCount();

let previousSiblingCount = Math.min(page() - 1, siblingCount());
let nextSiblingCount = Math.min(count() - page(), siblingCount());

if (fixedItems() !== false) {
// ref to avoid wrong corretions
const previousSiblingCountRef = previousSiblingCount;
const nextSiblingCountRef = nextSiblingCount;

// Add back the difference between the opposite side and the sibling count
previousSiblingCount += Math.max(siblingCount() - nextSiblingCountRef, 0);
nextSiblingCount += Math.max(siblingCount() - previousSiblingCountRef, 0);

if (!_showFirst) nextSiblingCount++;
if (!_showLast) previousSiblingCount++;

// Check specifically if true and not "no-ellipsis"
if (fixedItems() === true) {
if (!showFirstEllipsis) nextSiblingCount++;
if (!showLastEllipsis) previousSiblingCount++;
}

//replace ellipsis if it would replace only one item
if (page() - previousSiblingCount - (showFirst() ? 2 : 1) === 1) {
showFirstEllipsis = false;
previousSiblingCount++;
}
});
if (count() - page() - nextSiblingCount - (showLast() ? 1 : 0) === 1) {
showLastEllipsis = false;
nextSiblingCount++;
}
}

return {
showFirst: _showFirst,
showLast: _showLast,
showFirstEllipsis,
showLastEllipsis,
previousSiblingCount,
nextSiblingCount,
renderItemsDirectly,
};
});

return (
<>
<Show when={showFirst()}>{context.renderItem(1)}</Show>

<Show when={showFirstEllipsis()}>{context.renderEllipsis()}</Show>

<For each={[...Array(previousSiblingCount()).keys()].reverse()}>
{(offset) => <>{context.renderItem(context.page() - (offset + 1))}</>}
</For>

{context.renderItem(context.page())}

<For each={[...Array(nextSiblingCount()).keys()]}>
{(offset) => <>{context.renderItem(context.page() + (offset + 1))}</>}
</For>

<Show when={showLastEllipsis()}>{context.renderEllipsis()}</Show>

<Show when={showLast()}>{context.renderItem(context.count())}</Show>
<Show
when={items().renderItemsDirectly}
fallback={
<>
<Show when={items().showFirst}>{context.renderItem(1)}</Show>

<Show when={items().showFirstEllipsis}>
{context.renderEllipsis()}
</Show>

<For
each={[...Array(items().previousSiblingCount).keys()].reverse()}
>
{(offset) => (
<>{context.renderItem(context.page() - (offset + 1))}</>
)}
</For>

{context.renderItem(context.page())}

<For each={[...Array(items().nextSiblingCount).keys()]}>
{(offset) => (
<>{context.renderItem(context.page() + (offset + 1))}</>
)}
</For>

<Show when={items().showLastEllipsis}>
{context.renderEllipsis()}
</Show>

<Show when={items().showLast}>
{context.renderItem(context.count())}
</Show>
</>
}
>
<For each={[...Array(context.count()).keys()]}>
{(page) => <>{context.renderItem(page + 1)}</>}
</For>
</Show>
</>
);
}
2 changes: 1 addition & 1 deletion packages/core/src/pagination/pagination-root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ export function PaginationRoot<T extends ValidComponent = "nav">(
isDisabled: () => local.disabled ?? false,
renderItem: (page) => local.itemComponent({ page }),
renderEllipsis: local.ellipsisComponent,
page: state[0] as Accessor<number>,
page: () => Math.min(state[0]() ?? 1, local.count),
setPage: state[1] as Setter<number>,
};

Expand Down

0 comments on commit c0028e5

Please sign in to comment.