Skip to content

Commit

Permalink
Support all-day events (#306)
Browse files Browse the repository at this point in the history
* Change old ref API by createRef

* Change calculateDaysArray return type

Return string instead of moment object

* Simplify Title component

* Implement all-day events

* Change defaults in App

* Fix horizontal-swipe test

* Add all-day-event description style

* Update docs with all-day events

Add dedicated guide
Add props and special field
  • Loading branch information
pdpino authored Jun 6, 2023
1 parent 2817e54 commit 5705ac5
Show file tree
Hide file tree
Showing 31 changed files with 917 additions and 360 deletions.
21 changes: 17 additions & 4 deletions example/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ const sampleEvents = [
buildEvent(1, 3, 'red', {resolveOverlap: 'lane'}),
buildEvent(-18, 48 + 5, 'green', {eventKind: 'block'}),

buildEvent(0 - 24, 2, 'blue', {
allDay: true,
description: 'Long description is wrapped',
}),
buildEvent(1, 3, 'red', {allDay: true}),
buildEvent(-18, 48 + 5, 'green', {allDay: true}),

// Next week
buildEvent(24 * 7, 2, 'magenta'),
buildEvent(24 * 7 - 48, 3, 'green', {
Expand All @@ -35,10 +42,18 @@ const sampleEvents = [
disableLongPress: true,
}),
buildEvent(24 * 7 + 6, 6, 'brown', {resolveOverlap: 'ignore'}),
buildEvent(24 * 7 + 13, 2, 'lightgreen', {
allDay: true,
description: 'Long description is wrapped',
}),
buildEvent(24 * 7 - 18, 48 + 5, 'lightgreen', {allDay: true}),

// Two more weeks
buildEvent(48 * 7, 2, 'pink'),
buildEvent(48 * 7 - 54, 4, 'green'),
buildEvent(48 * 7 + 1, 3, 'lightgreen', {allDay: true}),

// Many events
// ...Array.from({length: 1000}, (_, i) =>
// buildEvent(24 + i * 5, 2, 'lightblue'),
// ),
Expand Down Expand Up @@ -70,9 +85,7 @@ const MyRefreshComponent = ({style}) => (
<Text style={[style, {fontSize: 20, color: 'black'}]}>Loading...</Text>
);

const DRAG_EVENT_CONFIG = {
afterLongPressDuration: 1000,
};
const DRAG_EVENT_CONFIG = null;

const EDIT_EVENT_CONFIG = {
top: true,
Expand Down Expand Up @@ -210,7 +223,7 @@ const App = ({}) => {
onEditEvent={onEditEvent}
editEventConfig={EDIT_EVENT_CONFIG}
dragEventConfig={DRAG_EVENT_CONFIG}
runOnJS
runOnJS={false}
/>
</SafeAreaView>
</>
Expand Down
11 changes: 2 additions & 9 deletions src/Events/Events.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,7 @@ import {
GridRowPropType,
GridColumnPropType,
} from '../utils/types';
import {
calculateDaysArray,
DATE_STR_FORMAT,
availableNumberOfDays,
} from '../utils/dates';
import { calculateDaysArray, availableNumberOfDays } from '../utils/dates';
import { topToSecondsInDay as topToSecondsInDayFromUtils } from '../utils/dimensions';
import { ViewWithTouchable } from '../utils/gestures';

Expand All @@ -42,10 +38,7 @@ const processEvents = (
// example: [[event1, event2], [event3, event4], [event5]], each child array
// is events for specific day in range
const dates = calculateDaysArray(initialDate, numberOfDays, rightToLeft);
return dates.map((date) => {
const dateStr = date.format(DATE_STR_FORMAT);
return resolveEventOverlaps(eventsByDate[dateStr] || []);
});
return dates.map((date) => resolveEventOverlaps(eventsByDate[date] || []));
};

const Lines = ({ initialDate, times, timeLabelHeight, gridRowStyle }) => {
Expand Down
63 changes: 63 additions & 0 deletions src/Header/AllDayEvent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Text, TouchableOpacity } from 'react-native';

import styles from './AllDayEvent.styles';
import { EventPropType } from '../utils/types';

const AllDayEventDefaultComponent = ({ event }) => (
<Text numberOfLines={1} ellipsizeMode="tail" style={styles.description}>
{event.description}
</Text>
);

const AllDayEvent = ({
event,
onPress,
onLongPress,
left,
width,
top,
containerStyle,
EventComponent = AllDayEventDefaultComponent,
}) => {
const onPressWrapper =
!event.disablePress && onPress && (() => onPress(event));
const onLongPressWrapper =
!event.disableLongPress && onLongPress && (() => onLongPress(event));

return (
<TouchableOpacity
key={event.id}
onPress={onPressWrapper}
onLongPress={onLongPressWrapper}
disabled={!onPressWrapper && !onLongPressWrapper}
style={[
styles.container,
{
left,
width,
top,
backgroundColor: event.color,
},
containerStyle,
event.style,
]}
>
<EventComponent event={event} />
</TouchableOpacity>
);
};

AllDayEvent.propTypes = {
event: EventPropType.isRequired,
left: PropTypes.number.isRequired,
width: PropTypes.number.isRequired,
top: PropTypes.number.isRequired,
containerStyle: PropTypes.object,
EventComponent: PropTypes.elementType,
onPress: PropTypes.func,
onLongPress: PropTypes.func,
};

export default React.memo(AllDayEvent);
12 changes: 12 additions & 0 deletions src/Header/AllDayEvent.styles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { StyleSheet } from 'react-native';

const styles = StyleSheet.create({
container: {
position: 'absolute',
},
description: {
fontSize: 14,
},
});

export default styles;
71 changes: 71 additions & 0 deletions src/Header/AllDayEvents.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import React from 'react';
import PropTypes from 'prop-types';
import Animated, {
useAnimatedStyle,
withTiming,
} from 'react-native-reanimated';

import AllDayEvent from './AllDayEvent';
import styles from './AllDayEvents.styles';
import {
AllDayEventsWithMetaPropType,
ReanimatedSharedValue,
} from '../utils/types';

// NOTE: event height is hard-coded!
export const ALL_DAY_EVENT_HEIGHT = 20;

const AllDayEvents = ({
allDayEvents,
days,
dayWidth,
style,
visibleHeight,
eventContainerStyle,
EventComponent,
onEventPress,
onEventLongPress,
}) => {
const animatedHeight = useAnimatedStyle(() => ({
height: withTiming(visibleHeight.value, { duration: 100 }),
}));
return (
<Animated.View style={[styles.container, style, animatedHeight]}>
{days.map((day, dayIndex) => {
const events = allDayEvents[day] || [];
return events.map(({ ref: event, overlap }) => {
const { lane, width: nDays } = overlap;
return (
<AllDayEvent
key={event.id}
event={event}
onPress={onEventPress}
onLongPress={onEventLongPress}
left={dayWidth * dayIndex}
width={dayWidth * nDays}
top={lane * ALL_DAY_EVENT_HEIGHT}
containerStyle={eventContainerStyle}
EventComponent={EventComponent}
/>
);
});
})}
</Animated.View>
);
};

AllDayEvents.propTypes = {
allDayEvents: PropTypes.objectOf(
PropTypes.arrayOf(AllDayEventsWithMetaPropType),
).isRequired,
days: PropTypes.arrayOf(PropTypes.string),
dayWidth: PropTypes.number.isRequired,
style: PropTypes.object,
eventContainerStyle: PropTypes.object,
EventComponent: PropTypes.elementType,
visibleHeight: ReanimatedSharedValue,
onEventPress: PropTypes.func,
onEventLongPress: PropTypes.func,
};

export default AllDayEvents;
11 changes: 11 additions & 0 deletions src/Header/AllDayEvents.styles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { StyleSheet } from 'react-native';

const styles = StyleSheet.create({
container: {
flexDirection: 'row',
alignItems: 'flex-start',
borderBottomWidth: 1,
},
});

export default styles;
Loading

0 comments on commit 5705ac5

Please sign in to comment.