React-native-calendars: More powerful theming

Created on 16 Jul 2017  路  16Comments  路  Source: wix/react-native-calendars

I would like to use this great component in an app that used bold fonts by default. The current theming options don't allow overriding the font weight.

I think it would be nice if we could override all the styles, by passing in a React.StyleSheet object. This means that we could override things such as font weights, margins, paddings etc. It would also make sure that theming is flexible enough without having to add separate theme options for each item.

I think this would be a more flexible and future-friendly way to go about theming. What do you guys think?

Feature request

Most helpful comment

Hey, I have extended API so that now it is possible to pass custom day component via props:

https://github.com/wix/react-native-calendars#overriding-day-component

All 16 comments

This request is similar to #10. It is hard to provide maximum flexibility without compromising api. Overriding styles directly would mean interfering with implementation details of library directly and because of that there would be a lot of design bugs introduced as library evolves. Also I want to provide api that always gives nice results. If user can override any style prop there will be many github issues created about broken calendar look and feel that would be caused by users modifying styles in unexpected ways.

I'm open for suggestions how more flexible theming could be implemented

As this has been linked in with issue #139 I would say the first suggestion is to remove any fontWeight whenever there is a defined fontFamily - kind of defeats having custom fonts IMO.

Hmm yeah, good points @tautvilas. I agree that is is hard to find the balance between flexibility and a nice interface here.

I think we can look at the calendar and determine the elements that it is comprised of. For example: Day, DayNumber, DayTitle, MonthTitle, PreviousArrow, NextArrow etc.

Each of these elements then has its own style options. If you look at the current theming options there are already a lot of variables that can be grouped together. For example: textDayFontFamily + textDayFontSize, textDayHeaderFontSize + textDayHeaderFontFamily.

This could perhaps be turned into an API like this:

<Calendar elementStyles={elementStyles} />

const elementStyles = StyleSheet.create({
  day: {
    // User can style the day box here
  },
  daySelected: {
    // User can style the selected day box here
  },
  dayNumber: {
    // User can style the day number here
  },
  dayNumberSelected: {
    // User can style the selected day number here
  },
  dayTitle: {
    // User can style the day box here
  }
}

The Calendar component then merges it's internal styles with the user styles using spread syntax. The keys don't necessarily have to be the same of course. This has the following upsides:

  1. Allows the user to override practically everything that you allow to override
  2. Uses the default React Native styling options, so it doesn't blow up the theme prop with separate keys.
  3. It still allows the Calendar component to override user provided styles where appropriate. For example, you could prevent the user from overriding 'opacity' on a certain element.

I just checked https://github.com/christopherdro/react-native-calendar, and it uses the same theming options I mentioned.

100% agree that @wvteijlingen's approach is the way to go. This should allow anyone to override anything while still allowing this module to ship with its own default look and feel.

This can be done without interfering with implementation details.

I have to agree with @wvteijlingen and @aforty, the way react-native-calendar gives styling options is the exact same I was talking in #191, and the one I think is the best, both for flexibility and for API (cause we will use the native stylesheet API). I understand that you guys don't want to be always telling people that the calendar is broken cause they broke it.
The solution I propose is to just have the essential styling that in the end will always override what the user puts in, and have a default theme that let's users override things that don't affect how the calendar works.

This way it will be easier to use for two reasons:

  • Easier to override styling props by using the real stylesheet prop names instead of "proprietary ones"

  • Remove some complexity from the code as we will be removing the lines where the decision of what styles to apply happens

And yeah, that would obviously be a breaking change

Hello all, I have added possibility to have complete flexibility over styles. However keep in mind that your style changes could be easily broken by new versions of library.

How to use it: find a style file that you want to modify, identify the STYLESHEET_ID for it.
Add your style settings to theme[STYLESHEET_ID].

It is not ideal but should discourage people from forking a lib just because they want to tweak a few style options.

Example:

https://github.com/wix/react-native-calendars/blob/master/src/calendar/header/style.js#L4
https://github.com/wix/react-native-calendars/blob/master/example/src/screens/calendars.js#L56

What do you think about this solution?

https://github.com/wix/react-native-calendars#advanced-styling

Hi @tautvilas, I think that's not the best solution but it is the doable one (at list in this version). Just a question, I haven't had the time to fiddle though the code after you adding this, this solves part of the problem, however, is doesn't solve the problem of styling within markedDates, or does it?

Thanks for your support in all this discussion!

Hey, since you can override style sheet of basic day and interactive day components you can modify styling of marked dates to certain degree

Hi @tautvilas, I agree with what you said here...

It is not ideal but should discourage people from forking a lib just because they want to tweak a few style options.

However, we are having an issue styling "day.basic.Day" component when using the "Agenda". We need access to its container style when its state is equal to "today". IE we would like to draw a circle to highlight "today" around the date text. Here are some possible suggestions.

One hacky solution would be to override the getDayComponent() method by creating a ref to the Agenda component and its associated "this.calendar". Then we could create a HoC that wraps "day.basic.Day", which adds the proper highlight based on the state being "today".

Another solution would be to expose a new container style when the Day component's state is "today". Maybe call it "todayContainerStyle". This would be an easy PR.

In my opinion, the best solution would be something similar to exposing a renderDay() property. Besides the aforementioned PR not being very generic, is there any work being done in this area? Seems like the perfect extension point exists here when exposing a property named "renderDay()".

@affablebloke +1 to that, completely exposing render (render props pattern) would end with all of this "lack of flexibility" complains

Hey, I have extended API so that now it is possible to pass custom day component via props:

https://github.com/wix/react-native-calendars#overriding-day-component

Thanks for such a quick turn around.

Unfortunately 'dateString' as shown in the example provided above is undefined. It is in the props as 'children'.

Example props:
{ "state": "today", "theme": { "agendaKnobColor": "#44B8BB", "dotColor": "#44B8BB", "selectedDayBackgroundColor": "#44B8BB", "selectedDayTextColor": "white", "todayTextColor": "#44B8BB" }, "date": { "year": 2017, "month": 11, "day": 23, "timestamp": 1511395200000, "dateString": "2017-11-23" }, "marking": { "marked": true }, "children": 23 }

Also, for Agenda, the onPress callback is not provided so selecting the date does not function properly.

I will update the docs it should be date.day not sure If I understand what you wrote about Agenda

I will try to explain myself better:
When using an Agenda there is a Calendar above the list. When you select a day in the calendar it calls the onPress of the TouchableOpacity if you use the default day component. When I override that component I need to be able to reference that function to select the day.

return ( <TouchableOpacity style={containerStyle} onPress={this.onDayPress}> <Text style={textStyle}>{dayText}</Text> {dot} </TouchableOpacity>

I need this.onDayPress to be the one from inside the context of the calendar or it doesn't work.

Everything else works great but I can't select a day in the calendar to change dates.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

kewin1807 picture kewin1807  路  4Comments

idlework picture idlework  路  4Comments

anishtr4 picture anishtr4  路  3Comments

akhilsanker picture akhilsanker  路  4Comments

nickitatkach picture nickitatkach  路  4Comments