项目作者: TomasHubelbauer

项目描述 :
An experiment in making RBC month view collapse items into represenatives per kind
高级语言: TypeScript
项目地址: git://github.com/TomasHubelbauer/rbc-month-view-slot-grouping-by-type.git


React Big Calendar Month View Slot Grouping By Type

Online demo

For a project I am working on, I need to have an option to adjust RBC to display
a different version of month view than it does by default. I am going to see if
I can prototype a standalone solution to that before I attempt to integrate the
changes needed to support it in my project.

By default, the RBC week view looks like this:

A month view containing the above week then looks like this:

In my project, slots of the calendar can have multiple types and are color-coded.
In the screenshots above, which come from the
RBC demo app,
there is only one kind of a slot (in blue color).

The change I am looking to implement entails grouping all items of the same type
to a single slot and displaying the number of items in the group on that one
slot.

RBC month view will display up to three slots in a day cell of the month view.
Coincidentally, I know I will only ever have three types of slots in my application.
So after grouping, I should never run into a case where the +X more links gets
displayed. I can hide that using CSS, then, but the grouping itself I think I
will be best off doing using a custom implementation provided to one of the RBC’s
components prop fields. I am not sure which one, yet.

I do not want to change the data model in the component which displays RBC as it
would require hoisting the logic which deals with view change and data restructuring
for the given view up. This is something I want to avoid as I consider the current
calendar view to be an encapsulated concern of the calendar component which
components which host it should have no information about unless they want to
hook additional logic up to that which affects their own state and presentation,
not just the calendars.

I’m going to start by scaffolding a new Create React App instance from a template.
npx create-react-app . --typescript.

CRA being annoying, it will require README.md and the image files to be temporarily
moved to another directory and then moved back after it has scaffolded its files,
because it is not smart enough to realize they would not conflict.

After scaffolding the application and cleaning it up a bit (removing useless files,
rewriting questionable syntax to a more appropriate way the way I view the world),
we are ready to integrate RBC into the project.

npm install --save react-big-calendar moment is followed by
npm install --save-dev @types/react-big-calendar because Moment bundles its
own types in its package, as it should. We need Moment because RBC won’t work
without a localizer and Moment is the easiest choice for a demo like this one.

Do not forget to include RBC styles in App.tsx so that the calendar is not
broken.

With a few lines we can demonstrate a week view calendar with a number of events
and upon switching to the month view we see the preview + expansion link mode.


The next objective is to demonstrate slots of multiple kinds. We can get rid of
the default Event type and provide our own to RBC as the component is generic.
If we keep the names of the start and end fields, we do not need to provide
accessor props for it, so we will do that to keep things simple.

To render the slots differently based on the kind property, we need to implement
a custom eventWrapper component prop field. Since the children passed in
the props of that wrapper component are absolutely positioned (at least in the
week view), we cannot just wrap them in another div with a certain background
color, as it would end up stacked at the top of the week day column.

Instead, we will make use of React.Children.only and adjust the props of the
passed-in div to extend its className.

We can now verify both the week view and the month view show correctly color-
coded slots.


To start figuring out how the month view could be adapted to group the slots and
display only one representative slot for each kind which has members, we will
take a look at the RBC documentation.

By that, I of course mean the RBC typings, as the actual RBC documentation for
the components prop is rather… scarce:

http://intljusticemission.github.io/react-big-calendar/examples/index.html#prop-components

So what do we have in the component prop typings?

https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react-big-calendar/index.d.ts#L134

event and eventWrapper both deal with the individual slots. On top of that,
the field month for month view specific overrides does not include anything
which looks like it would be a component for the month view cell.

We do have eventContainerWrapper there so let’s figure out what that does.
By cloning the sole child element and appending a marker class to its className
prop, we are able to identity that in the week view, this is a div which
encapsulates all the individual event wrappers in the day column.
Unfortunately this component is never called for the month view.

Applying the same technique (an extra, marker class) and querying the DOM with
document.querySelectorAll, we find that dateCellWrapper is a component which
gets called for each cell of the month view calendar. We can scope it to just it
by nesting it in the month field of the components prop.

Unfortunately the typings here lack this particular component underneath the
month field so we have to enter any-territory.

  • Create a PR for components

We also find that this particular component doesn’t receive any props containing
the models of the events to be displayed. It is merely a background cell which
we can adjust, but the actual contents of the calendar are still handled by
event and eventWrapper but not eventContainerWrapper.

Our best bet here is to completely disable the events by overriding eventWrapper
for month and returning null for each invocation. This will render the
calendar empty and we can then adjust the dateCellWrapper implementation so it
computes and materializes the representative events on the fly base on the calendar
events prop.

We also need to hide the +X more link, which luckily for us has a CSS class
rbc-show-more so we can hide it using plain CSS with a selector with higher
specificity than the one from RBC. We do not need to rely on extensibility points
provided by RBC, which we already know it doesn’t have enough of to enable us to
hide this link using other means.


With all of the above done, we can now marvel at our creation:

The published artifacts can be found on GitHub Pages:

Online demo