Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v5 component refactor: Pagination #245

Open
11 tasks
HollyJoyPhillips opened this issue Dec 9, 2024 · 8 comments
Open
11 tasks

v5 component refactor: Pagination #245

HollyJoyPhillips opened this issue Dec 9, 2024 · 8 comments
Labels
feature The issue relates to a new feature v5 Issues for v5 release

Comments

@HollyJoyPhillips
Copy link

As part of the v5 Elements release, each component will be reviewed and refactored to ensure best practice and design system alignment

Specification

Developer Checklist

  • Styles alignment between Design System and Elements
  • Check design tokens in Figma and implement CSS variable tokens if available for relevant component
  • Align with accessibility standards / spec as per above
  • If relevant, break down component into Styles Only and React component structures
  • Ensure all variants of components are documented as appropriate
  • Ensure unit test coverage is adequate for component
  • Update documentation in MDX file as per guidelines
  • Changelog updated to reflect a single beta version per component ideally

Release Checklist

  • Approved PR merged to main
  • Design & product review and feedback addressed by developer
  • Beta release by product / engineering lead to next beta version
@HollyJoyPhillips HollyJoyPhillips added feature The issue relates to a new feature v5 Issues for v5 release labels Dec 9, 2024
@github-project-automation github-project-automation bot moved this to To Review in Elements Roadmap Dec 9, 2024
@HollyJoyPhillips HollyJoyPhillips moved this from To Review to Todo in Elements Roadmap Dec 9, 2024
@ss-dimasm
Copy link
Contributor

ss-dimasm commented Dec 30, 2024

FYI @kurtdoherty @ksolanki7

Proposed Solution Design - Pagination

Component Structure

Pagination is better suited for use with the Provider pattern. This pattern requires cloning the state to synchronize details across components, and to ensure the composed component should be used within a correct parent. Here is a simple POC for Pagination using the Provider pattern

1. Pagination
Outlines the core concept of a Pagination component, typically implemented using a nav element in the DOM

  • Purpose:

    • Setup and manages the internal state of pagination that will be shared across the composed component
    • Serves as the entry point for other, more specific composed components (e.g., "Backward," "Forward" buttons)
  • Key Properties:

Prop Description
initialPage The initial page to display when the pagination component first mount
maxPages The maximum number of pages allowed. The internal state cannot exceed this

2. Pagination.BackwardButton
Registered as an atom component, this button represents the "Backward" button within a Pagination component. It is implemented using a 'button' element and handles state synchronization with the internal pagination component behind the scenes

  • Purpose:

    • Handles the "back" behavior within a Pagination component
    • Provides a visually appealing button with an icon (e.g., chevronLeft in Elements Icon)
  • Implementation:

    • Built upon the button HTML element
    • Extends the ButtonHTMLAttributes<HTMLButtonElement> interface from React, inheriting its properties
    • Requires an essential onClick prop to define the action triggered when the button is clicked

3. Pagination.ForwardButton
Similar like Pagination.BackwardButton but it's deliberately focused on "Forward" behavior

  • Purpose:

    • Handles the "next" behavior within a Pagination component
    • Provides a visually appealing button with an icon (e.g., chevronRight in Elements Icon)
  • Implementation:

    • Built upon the button HTML element
    • Extends the ButtonHTMLAttributes<HTMLButtonElement> interface from React, inheriting its properties
    • Requires an essential onClick prop to define the action triggered when the button is clicked (e.g., incrementing the current page)

4. Pagination.PageIndicator
Display the current page number that managed internally from a pagination state

  • Purpose:

    • Visually indicates the currently active page to the user
    • Often displays information such as "Page 1 of 10" or "Showing 1-10 of 50 results."
  • Suggestion:

    • Create two versions of PageIndicator. The static version renders the active page immediately in the format "1 of 10". The dynamic version provides greater flexibility, allowing users to customize the page text display through a "render children" pattern, enabling options like "Page 1"

Example

Usage with Static PageIndicator

<Pagination initiatePage={1} totalPages={10}>
  <Pagination.BackwardButton
    onClick={(page) => handleOnBackButton(page)}
  />
  <Pagination.PageIndicator/>
  <Pagination.ForwardButton
    onClick={(page) => handleOnForwardButton(page)}
  />
</Pagination>

Usage with Dynamic PageIndicator

<Pagination initiatePage={1} totalPages={10}>
  <Pagination.BackwardButton
    onClick={(page) => handleOnBackButton(page)}
  />
  <Pagination.PageIndicator>
    {({ currentPage }) => `Page ${currentPage}`}
  </Pagination.PageIndicator>
  <Pagination.ForwardButton
    onClick={(page) => handleOnForwardButton(page)}
  />
</Pagination>

Preview

2024-12-30_09-45-28.mp4

@kurtdoherty
Copy link
Contributor

@ss-dimasm thanks for the considerable effort on this solution design. I can see you've gone to a lot of thought putting this together and communicating the "why" behind each of the components you're proposing. 👏

While I appreciate the level of flexibility you've tried to bake into this, I think the proposal is currently over-engineered.

  • I think it's too early for us to be managing pagination state for products. Different products may take different approaches to tracking the current page (e.g. a URL search param vs local component state). Until we see how product engineering teams want to implement this kind of state management and determine whether any of it can be standardised within Elements, I think Elements should just focus on providing a presentational Pagination component and leave the state management to the consumer.
  • While I recognise a lot of the components you've worked on recently have taken a compositional approach, I don't think we need that here. Given the simplicity of this component, and the lack of any variation in the design spec, I think its reasonable to provide a single <Pagination /> component to represent this molecule.

Given these two comments, I would suggestion the following simplification:

interface PaginationProps {
  currentPage: number
  onPageChange: (nextPage: number) => void
  pageCount: number
}

@ss-dimasm
Copy link
Contributor

thanks, @kurtdoherty. yes my initial assumption was that pagination would be isolated within the component, and consumers could use it as they wanted (like the POC)

However, considering your concern that "different products may take different approaches" is also valid, and it seems that simplification for Pagination would make it more beneficial for this case, especially since the Elements would then be responsible for the UI representation instead of managing state within a component

Talking about the compositional approach, it may not needed when we only want the Pagination to deliver the UI presentational; might be better to put it within the component itself

@DanishAli-Reapit DanishAli-Reapit self-assigned this Jan 10, 2025
@DanishAli-Reapit DanishAli-Reapit moved this from Todo to In Progress in Elements Roadmap Jan 10, 2025
@DanishAli-Reapit DanishAli-Reapit moved this from In Progress to Todo in Elements Roadmap Jan 10, 2025
@ss-dimasm
Copy link
Contributor

Hey @kurtdoherty , I've made an update on this, still in the same POC link as per above but I'll highlight the change below

pagination_screenshot

So, generally from a user's perspective, if we do this, it would make migration to the v5 elements simpler, since it's nearly "have the same API" as before; but IMO in terms of code I think we could put some in the atoms (i.e. PaginationForwardButton) they have their own responsibility while displaying the user interface

example usage

<Pagination
  currentPage={page}
  pageCount={TOTAL_PAGES}
  onPageChange={setPage}
/>

@kurtdoherty
Copy link
Contributor

kurtdoherty commented Jan 16, 2025

@ss-dimasm I don't have any strong opinions on whether you have intermediary components for the next page and previous page buttons, just so long as they're not exported for use (personally, I don't think they're needed, but 🤷). For now, I think we would just want the styled components (ElPaginationButton etc) exported alongside the main Pagination React component.

@ss-dimasm
Copy link
Contributor

it's fair @kurtdoherty , I'm assuming we've found the solution for pagination, and let's see how it will be constructed with production grade 🤔

@kurtdoherty
Copy link
Contributor

@ss-dimasm Please note the updates Andrei has made to the design spec. They no longer have custom "Navigation button" components, rather they're using the standard Button component. This means we can do the same.

@ss-dimasm
Copy link
Contributor

that would be handy, I'll take a note of that 👍 @kurtdoherty

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature The issue relates to a new feature v5 Issues for v5 release
Projects
Status: Todo
Development

No branches or pull requests

4 participants