Giter VIP home page Giter VIP logo

react-native-swipe-calendar's Introduction

React Native Swipe Calendar

A swipeable calendar component for React Native.
Fully native interactions powered by Reanimated 2 and React Native Gesture Handler.

SwipeCalendar demo

Install

  1. Follow installation instructions for reanimated and react-native-gesture-handler
  2. npm install or yarn add react-native-swipe-calendar
  3. import Calendar from 'react-native-swipe-calendar'

Props

type HeaderComponent = (props: { date: Date }) => JSX.Element | null;

type DayLabelComponentType = (props: { date: Date }) => JSX.Element | null;

type DayComponentType = (props: {
  date: Date;
  isInDisplayedMonth: boolean;
  isSelected: boolean;
  isToday: boolean;
}) => JSX.Element | null;

export type WeekComponentType = (props: {
  days: Date[];
}) => JSX.Element | null;

export type MonthComponentType = (props: {
  weeks: Date[][];
  firstDayOfMonth: Date;
}) => JSX.Element | null;

export type PageInterval = "day" | "week" | "month";

export type CalendarProps = {
  selectedDate?: Date | null; 
  onDateSelect?: OnDateSelect;
  onPageChange?: (date: Date) => void;
  currentDate?: Date;
  HeaderComponent?: HeaderComponentType;
  DayLabelComponent?: DayLabelComponentType;
  DayComponent?: DayComponentType;
  WeekComponent?: WeekComponentType;
  MonthComponent?: MonthComponentType;
  theme?: Partial<typeof DEFAULT_THEME>;
  pageBuffer?: number;
  minDate?: Date;
  maxDate?: Date;
  pageInterpolator?: CalendarPageInterpolator;
  simultaneousGestures?: (ComposedGesture | GestureType)[];
  monthAnimCallbackNode?: Animated.SharedValue<number>;
  gesturesDisabled?: boolean;
  animationConfig?: Partial<WithSpringConfig>;
  weekStartsOn?: WeekDayIndex;
  pageInterval?: PageInterval;
};
Name Type Description
selectedDate `Date null`
onDateSelect (date: Date) => void Callback invoked when the a date is selected.
onPageChange (date: Date) => void Callback invoked when the month is changed.
currentDate Date Date to initialize the calendar with.
theme Partial<typeof DEFAULT_THEME> Overrides for default fonts and colors.
HeaderComponent HeaderComponentType Custom replacement for Header component.
DayComponent DayComponentType Custom replacement for Day compoent.
WeekComponent WeekComponentType Custom replacement for Week compoent.
MonthComponent MonthComponentType Custom replacement for Month compoent.
DayLabelComponent DayLabelComponentType Custom replacement for Day Label component ("Su", "Mo", etc).
minDate Date The minimum date the calendar will display
maxDate Date The maximum date the calendar will display
pageInterpolator typeof defaultPageInterpolator A worklet to customize page transition animations. Returns an animated style
animationConfig Partial<WithSpringConfig> An animation spring config object to customize how page transitions animate.
simultaneousGestures `(ComposedGesture GestureType)[]`
weekStartsOn number Index of the day week starts on.
pageInterval `"month" "week"

Imperative Api

Access the imperative api by passing a ref to the Calendar component:

type ImperativeApiOptions = {
  animated?: boolean;
}

type CalendarImperativeApi = {
  incrementPage: (options?: ImperativeApiOptions) => void;
  decrementPage: (options?: ImperativeApiOptions) => void;
  setPage: (date: Date, options?: ImperativeApiOptions) => void;
}

// Example
function MyComponent() {

  const calendarRef = useRef<CalendarImperativeApi>(null)
  const onIncrementButtonPress = () => calendarRef.current?.incrementPage()
  
  return (
    <>
     <Calendar ref={calendarRef} />
     <MyButton onPress={onIncrementButtonPress} />
    </>
  )
}
Name Type Description
incrementPage (options: ImperativeApiOptions) => void Go to next month.
decrementPage (options: ImperativeApiOptions) => void Go to previous month.
setPage (date: Date, options: ImperativeApiOptions) => void Go to given month.

Hooks

If you render your own components via DayComponent prop or other custom view, you may need access to more internal state than is available on props. This state may be accessed via the exported useCalendarContext() hook.

NOTE: Be careful about performance! Lots of instances of DayComponent are rendered at any given time. You may need to wrap memoized inner wrappers around your custom components.

type CalendarContextValue = {
  referenceDate: Date,
  selectedDate: Date | null | undefined,
  onDateSelect: OnDateSelect,
  DayComponent:  DayComponentType | undefined,
  WeekComponent:  WeekComponentType | undefined,
  MonthComponent:  MonthComponentType | undefined,
  DayLabelComponent: DayLabelComponentType | undefined,
  HeaderComponent: HeaderComponentType | undefined,
  theme: typeof DEFAULT_THEME,
  pageInterpolator: typeof defaultPageInterpolator,
  weekStartsOn: number,
}

// Example
function MyCustomDayComponent({ date, isSelected }) {
  const { onDateSelect } = useCalendarContext()
  
  // Forward to the `onDateSelect` prop
  const onDayPress = () => onDateSelect(date, { isSelected })
  
  return (
  <TouchableOpacity onPress={onDayPress}>
    <Text>
      {date.getDate()}
    </Text>
  </TouchableOpacity>
  )
}

Custom pageInterpolator

The pageInterpolator prop enables customization of page animations using a Reanimated "worklet" function. For example, the following pageInterpolator will scale up upcoming months and fade in as they enter, then rotate and fade out as they leave:

// Example
function pageInterpolator({ focusAnim }: CalendarPageInterpolatorParams) {
  "worklet"
  
  const inputRange = [-1, 0, 1]
  
  // Ensure the current month has a higher zIndex than the surrounding months
  const zIndex = interpolate(focusAnim.value, inputRange, [0, 99, 0])
  
  // Fade the current month as it enters/leaves focus
  const opacity = interpolate(focusAnim.value, inputRange, [0, 1, 0])
  
  // Rotate the current month as it leaves focus
  const rotationDeg = interpolate(focusAnim.value, inputRange, [360, 0, 0])
  
  // Scale up the incoming month
  const scale = interpolate(focusAnim.value, inputRange, [2, 1, 0.25])
  
  return {
    opacity,
    zIndex,
    transform: [{ rotate: `${rotationDeg}deg` }, { scale }]
  }
}

pageInterpolator demo

Example

https://snack.expo.dev/@computerjazz/react-native-swipe-calendar

import React, {
  useState,
  useRef,
} from "react";
import {
  Text,
  View,
  StyleSheet,
  LayoutAnimation,
  TouchableOpacity,
  Platform,
  UIManager,
} from "react-native";
import Calendar from "react-native-swipe-calendar";

if (Platform.OS === "android") {
  UIManager.setLayoutAnimationEnabledExperimental &&
    UIManager.setLayoutAnimationEnabledExperimental(true);
}

export default function App() {

  const [currentDate, setCurrentDate] = useState(new Date());
  const [selectedDate, setSelectedDate] = useState<Date | null>(null);
  const calendarRef = useRef(null);
  
  return (
    <View style={styles.container}>
      <Calendar
        theme={{ todayIndicatorDotColor: "blue" }}
        ref={calendarRef}
        currentDate={currentDate}
        onDateSelect={(date, { isSelected }) => setSelectedDate(isSelected ? null : date )}
        selectedDate={selectedDate}
        onPageChange={(date) => {
          setCurrentDate(date);
          LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
        }}
      />
      <View style={styles.controlBar}>
        <TouchableOpacity
          style={styles.incDec}
          onPress={() => calendarRef.current?.decrementPage()}
        >
          <Text>{"<"}</Text>
        </TouchableOpacity>
        <TouchableOpacity
          style={styles.incDec}
          onPress={() => calendarRef.current?.incrementPage()}
        >
          <Text>{">"}</Text>
        </TouchableOpacity>
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: { 
    flex: 1, 
    backgroundColor: "white", 
    paddingTop: 100 
  },
  incDec: {
    paddingHorizontal: 20,
    padding: 10,
    backgroundColor: "lightgrey",
    alignItems: "center",
    justifyContent: "center",
    borderRadius: 5,
  },
  controlBar: {
    position: "absolute",
    top: 100,
    left: 0,
    right: 0,
    flexDirection: "row",
    justifyContent: "space-between",
  },
});

react-native-swipe-calendar's People

Contributors

computerjazz avatar thecoorum avatar wilsongramer avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

react-native-swipe-calendar's Issues

TypeError: Cannot read property 'toString' of undefined

node_modules/react-native-reanimated/lib/reanimated2/hook/utils.js (line 42)

code

<Calendar
/>

iOS
"react-native": "0.68.2",
"react-native-reanimated": "^2.9.1",
"react-native-gesture-handler": "^2.5.0",
"react-native-swipe-calendar": "^0.0.19",

Support range selection

Seems to be great library, considering that other calendar modules are extremely slow. would be great to have such a feature

future of this package

This is an awesome project, great work!

Is there any plan to extend this project and add more features like expandable week view or marked dates and so on?
It would be a very good alternative to react-native-calendars which is for performance reasons not usable in my opinion.

Thanks!

Months overlapping each other

Hello and thank you for the nice lib!

Description

I noticed a bug when sometimes on render months are overlapping each other like on the screenshot

Update

As a resolution I used custom components for everything with the background the same as container background
Also seems like the month ago is displayed first

Expected

Months are rendering as they should, single in view

Media

IMG_E849545BBC41-1

IMG_0498.MP4

pageInterval=day component onPageChange triggers always start of month

Its always rendering same time which is start of month

also onDateSelect is not triggers how to know when the date change ?

      <Calendar   
        pageInterval="day"
        theme={{ todayIndicatorDotColor: 'blue', inactiveOpacity: 0.5 }}
        ref={calendarRef}           
        currentDate={currentDate}
        DayComponent={DayComponent}
        selectedDate={selectedDate}
        // currently showing 1 november if you go previous page like october than it shows 1 october etc.
        onPageChange={(date)=>alert(date.toDateString())} 
        monthAnimCallbackNode={monthAnimCallbackNode}
      /> 

tested in https://snack.expo.dev/@computerjazz/react-native-swipe-calendar

not working with hermes

If we use hermes as the default engine, we can swipe in the week for only 2 weeks and then the app would be unresponsive

Possibility to get support for Year navigation

Hello,

thanks for your library and working like a charm with multiple customisations. We have a requirement to navigate to previous/next years similar to months. When we used setPage its taking more than 10 seconds to load UI. Any suggestion from your end how can we achieve this?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.