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

feat: Introduced custom components "Months" #1917

Merged
merged 9 commits into from Oct 13, 2023
Merged

feat: Introduced custom components "Months" #1917

merged 9 commits into from Oct 13, 2023

Conversation

pawelgoc
Copy link
Contributor

Context

As developer I might want to wrap <DayPicker /> and use children API to map over months. For instance I would want to extend pagination to behave like carousel - this seems good use case for using Children.map.
To achieve it we need to be able to host collection of <Month /> elements. That's why replacing hardcoded months container by public customisable <Months /> open additional possibility how library can be consumed.

Analysis

const AnyComponent = ({children}) => {
  return <p>Count: {Children.count(children)}</p>
}
---
<AnyComponent>
  <DayPicker numberOfMonths={4} />
</AnyComponent/>

--- output
<p>Count: 1</p>

--- with custom Months
const CustomMonths = ({children}) => (<Months><AnyComponent>{children}</AnyComponent></Months>)

<DayPicker numberOfMonths={4} components={Months: CustomMonths}>

--- output
  <p>Count: 4</p>

Current implementation will always return only one children because in Root component DIV element is wrapper on top of months.

Solution

With custom <Months /> component we can have direct access to array children or to do any other customisation. It means library is more flexible without exposing core functionality.
We already can find dedicated classes and styles for months to allow customisation, that's makes me think that custom component <Months /> also make sense.

Other approach I've tried was to compose DayPicker form existing components like:

const DayPicker = () => {
  <Providers>
    <Root>
       <CustomMonths>{months.map(() => <Month />)}</CustomMonths>
    </Root>
  </Providers>
}

but it is also impossible because <Month /> is private (I believe for good reasons).

@gpbl
Copy link
Owner

gpbl commented Sep 30, 2023

Interesting, thanks for your contribution! Looking at it.

@gpbl gpbl self-assigned this Oct 7, 2023
@pawelgoc
Copy link
Contributor Author

pawelgoc commented Oct 9, 2023

Interesting, thanks for your contribution! Looking at it.

Hi @gpbl , do you have any feedback regarding this PR?
Curious if you are considering to merge it and eventually when (not sure If I should wait or rather rely on fork)?

@gpbl
Copy link
Owner

gpbl commented Oct 13, 2023

Thanks @pawelgoc I wanted to update a bit the code to match our code style. Thanks for you contribution, coming soon on npm!

@gpbl gpbl merged commit 811732b into gpbl:main Oct 13, 2023
10 checks passed
@gpbl
Copy link
Owner

gpbl commented Oct 13, 2023

(PS. if you are trying to add animation to the calendar - it is something we plan to add in v9. Would love to see your implementation)

@pawelgoc
Copy link
Contributor Author

(PS. if you are trying to add animation to the calendar - it is something we plan to add in v9. Would love to see your implementation)

I doubt our impl. will fit to library as it would require additional dependency.

Idea is to utilise pagination build in DayPicker + any library that serve Carousel functionality.
On DayPicker prop numberOfMonths is set to n + 2 where n is amount of months that will be visible in Carousel and remaining 2 months are just left and right offset. Having offsets will allow to animate transition between months and is done by Carousel.

Of course there is needed additional sync between both components to resolve what is current month and slideIndex.
There was also challange how to prevent focus on day that is in offset month which can be triggered by keyboard navigation (library API not allow to control / prevent focus() and default behaviour of focus is to scroll to element which destroy calculated positions by Carousel)

Simplified example:

const CustomMonths = ({children, props}) => {
    return (
      <Months>
        <Carousel {...props} >
          {children}
        </Carousel>
      </Months>
    );
}

const Component = ({...props}) => (<DayPicker
        {...props}
        numberOfMonths={numberOfMonthsPerPage + 2}
        month={currentMonth}
        components={{ ...props.components, Months: CustomMonths }}
  />)

How it looks:

day-picker-horizontal

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants