All files / components/Pagination Pagination.svelte

0% Statements 0/98
0% Branches 0/1
0% Functions 0/1
0% Lines 0/98

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99                                                                                                                                                                                                     
<script lang="ts">
  // TODO: use USWDS Pagination component styles
  import "./Pagination.scss";
  import { createEventDispatcher } from "svelte";
  export let currentPage: number;
  export let totalPages: number;
  export let getPageLink: (page: number) => string | undefined = () => undefined;

  const dispatch = createEventDispatcher<{
    paginationClick: {
      page: number;
    };
  }>();

  // Rules for numeric page links:
  // - 1 is always shown
  // - The last page (e.g., 9) is always shown
  // - The current page is always shown
  // - The two pages before the current page are always shown
  // - The two pages after the current page are always shown
  // - If the current page is less than or equal to 4, the first five pages are always shown
  // - If the current page is greater than or equal to the length minus 4, the last five pages are always shown
  // - Pages are never shown more than once
  //
  // These rules result in the following behavior given a list with 9 pages. Note that there will
  // always be either 6 or 7 numeric page links.
  //
  //            <[1]> [2]  [3]  [4]  [5]  ...  [9]  Next >          (6 number links)
  // < Previous  [1] <[2]> [3]  [4]  [5]  ...  [9]  Next >          (6 number links)
  // < Previous  [1]  [2] <[3]> [4]  [5]  ...  [9]  Next >          (6 number links)
  // < Previous  [1]  [2]  [3] <[4]> [5]  [6] ...  [9]  Next >      (7 number links)
  // < Previous  [1]  ...  [3]  [4] <[5]> [6]  [7] ...  [9]  Next > (7 number links)
  // < Previous  [1]  ...  [4]  [5] <[6]> [7]  [8]  [9]  Next >     (7 number links)
  // < Previous  [1]  ...  [5]  [6] <[7]> [8]  [9]  Next >          (6 number links)
  // < Previous  [1]  ...  [5]  [6] <[7]> [8]  [9]  Next >          (6 number links)
  // < Previous  [1]  ...  [5]  [6]  [7] <[8]> [9]  Next >          (6 number links)
  // < Previous  [1]  ...  [5]  [6]  [7]  [8] <[9]> Next >          (6 number links)

  $: shownPageLinkNumbers = [
    ...new Set([
      1,
      totalPages,
      currentPage - 2,
      currentPage - 1,
      currentPage,
      currentPage + 1,
      currentPage + 2,
      ...(currentPage < 4 ? [...Array(5).keys()].map((n) => n + 1) : []),
      ...(currentPage > totalPages - 4 ? [...Array(5).keys()].map((n) => totalPages - n) : []),
    ]),
  ]
    .filter((n) => n > 0 && n <= totalPages)
    .sort((a, b) => a - b);

  $: shownPageLinkNumbersWithLastNumber = shownPageLinkNumbers.map(
    (n, i, arr) => [n, i > 0 ? arr[i - 1] : null] satisfies [number, number | null],
  );

  const handleClickForPage = (page: number) => (e: MouseEvent) => {
    const succeeded = dispatch("paginationClick", { page }, { cancelable: true });
    if (!succeeded) e.preventDefault();
  };
</script>

<div class="ldaf-pagination">
  {#if currentPage > 1}
    <div class="ldaf-pagination__previous-button">
      <a
        href={getPageLink(currentPage - 1)}
        on:click={() =>
          dispatch("paginationClick", { page: currentPage - 1 }, { cancelable: true })}
        >{"<"} Previous</a
      >
    </div>
  {/if}
  <div class="ldaf-pagination__numeric-buttons">
    {#each shownPageLinkNumbersWithLastNumber as [pageLinkNumber, lastPageLinkNumber]}
      {#if lastPageLinkNumber && pageLinkNumber - lastPageLinkNumber > 1}
        <div class="ldaf-pagination__numeric-button ldaf-pagination__ellipsis">…</div>
      {/if}
      <a
        href={getPageLink(pageLinkNumber)}
        on:click={handleClickForPage(pageLinkNumber)}
        class="ldaf-pagination__numeric-button"
        class:ldaf-pagination__numeric-button--selected={pageLinkNumber === currentPage}
      >
        {pageLinkNumber}
      </a>
    {/each}
  </div>
  {#if currentPage < totalPages}
    <div class="ldaf-pagination__next-button">
      <a href={getPageLink(currentPage + 1)} on:click={handleClickForPage(currentPage + 1)}>
        Next >
      </a>
    </div>
  {/if}
</div>