Skip to content

Commit 5daf561

Browse files
artyorshmalashkevich
authored andcommitted
feat(calendar): component implementation (#153)
* feat(calendar): initial setup * feat(calendar): separated components * feat(calendar): boundingMonth prop * feat(calendar): update example * fix(calendar): months count to render in last year * fix(calendar): selection * refactor(calendar): separated week component * fix(calendar): selection optimizations * fix(calendar): selection optimizations - selection changes prop * fix(calendar): selection optimizations with shouldComponentUpdate * feat(calendar): day names component - base * feat(calendar): apply styles * feat(calendar): apply styles * feat(calendar): month header * feat(calendar): localized weekday & month names * fix(calendar): non-required selected date * feat(calendar): ranged calendar * fix(calendar): styles * feat(calendar): highlight today * feat(calendar): filter dates * feat(calendar): custom day render function * feat(calendar/range): custom day render function * feat(calendar): update example * refactor(calendar): move components to separate dirs * refactor(calendar): selection strategies * fix(calendar): cell selection after it was highlighted * fix(calendar): runtime warnings * fix(calendar): no-state-initialized warning * fix(calendar): day component key prop null-pointer * refactor(calendar): lint * feat(calendar): implementation examples * fix(calendar): month count rendering * feat(calendar): update examples * fix(calendar): render component after onLayout * refactor(calendar): month view as list item instead of year * feat(calendar): scrollTo* functions support * fix(calendar): month height calculation * feat(docs): update rkCalendar docs * feat(calendar): horizontal and vertical layout implementation * feat(calendar): add scrollTo next/prev month methods * feat(example): add horizontal calendar example * refactor(calendar): locale service with mocked data * fix(calendar): android - scroll to today on initial render * fix(calendar): bounding dates selection * docs(calendar): add layout prop description * feat(example): add calendar examples description * docs(calendar): add no-documented methods description and demo gif * refactor(calendar): style props to types refactor(calendar): move props to types refactor(calendar): rk-typed styles apply * refactor(calendar): render method as function * refactor(calendar): linebreaks * refactor(calendar): apply naming convenience * refactor(calendar): fix layout axis variables typo
1 parent 1492f41 commit 5daf561

35 files changed

+2258
-0
lines changed

docs/assets/gif/calendar-range.gif

1.32 MB
Loading

docs/structure.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,38 @@ export const STRUCTURE = [
8080
}
8181
]
8282
},
83+
{
84+
type: 'page',
85+
name: 'RkCalendar',
86+
demogif: 'calendar-range.gif',
87+
children: [
88+
{
89+
type: 'block',
90+
block: 'rk-description',
91+
klass: 'RkCalendar',
92+
},
93+
{
94+
type: 'block',
95+
block: 'rk-examples',
96+
klass: 'RkCalendar',
97+
},
98+
{
99+
type: 'block',
100+
block: 'rk-methods',
101+
klass: 'RkCalendar',
102+
},
103+
{
104+
type: 'block',
105+
block: 'rk-props',
106+
klass: 'RkCalendar',
107+
},
108+
{
109+
type: 'block',
110+
block: 'rk-styles',
111+
klass: 'RkCalendar',
112+
}
113+
]
114+
},
83115
{
84116
type: 'page',
85117
name: 'RkCard',

example/App.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ const ExplorerApp = StackNavigator({
1818
Home: { screen: Screens.ComponentsScreen },
1919
Picker: { screen: Screens.PickerScreen },
2020
Button: { screen: Screens.ButtonScreen },
21+
Calendars: { screen: Screens.CalendarScreen },
22+
BaseCalendar: { screen: Screens.BaseCalendarScreen },
23+
RangeCalendar: { screen: Screens.RangeCalendarScreen },
24+
BoundingCalendar: { screen: Screens.BoundingCalendarScreen },
25+
CustomCalendar: { screen: Screens.CustomCalendarScreen },
26+
HorizontalCalendar: { screen: Screens.HorizontalCalendarScreen },
2127
Switch: { screen: Screens.SwitchScreen },
2228
Choice: { screen: Screens.ChoiceScreen },
2329
Tab: { screen: Screens.TabScreen },

example/screens/ComponentsScreen.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ export class ComponentsScreen extends React.Component {
2727
}, {
2828
title: 'Buttons',
2929
route: 'Button',
30+
}, {
31+
title: 'Calendars',
32+
route: 'Calendars',
3033
}, {
3134
title: 'Switches',
3235
route: 'Switch',
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import React from 'react';
2+
import { View } from 'react-native';
3+
import {
4+
RkCalendar,
5+
RkStyleSheet,
6+
} from 'react-native-ui-kitten';
7+
8+
export class BaseCalendarScreen extends React.Component {
9+
static navigationOptions = {
10+
title: 'Base Calendar',
11+
};
12+
13+
render() {
14+
return (
15+
<View style={styles.container}>
16+
<RkCalendar
17+
min={new Date(2018, 0, 1)}
18+
max={new Date(2019, 0, 1)}
19+
/>
20+
</View>
21+
);
22+
}
23+
}
24+
25+
const styles = RkStyleSheet.create(theme => ({
26+
container: {
27+
flex: 1,
28+
backgroundColor: theme.colors.background,
29+
paddingHorizontal: 8,
30+
},
31+
}));
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import React from 'react';
2+
import { View } from 'react-native';
3+
import {
4+
RkCalendar,
5+
RkStyleSheet,
6+
} from 'react-native-ui-kitten';
7+
8+
export class BoundingCalendarScreen extends React.Component {
9+
static navigationOptions = {
10+
title: 'Bounding Month Calendar',
11+
};
12+
13+
render() {
14+
return (
15+
<View style={styles.container}>
16+
<RkCalendar
17+
min={new Date(2018, 0, 1)}
18+
max={new Date(2019, 0, 1)}
19+
boundingMonth={false}
20+
/>
21+
</View>
22+
);
23+
}
24+
}
25+
26+
const styles = RkStyleSheet.create(theme => ({
27+
container: {
28+
flex: 1,
29+
backgroundColor: theme.colors.background,
30+
paddingHorizontal: 8,
31+
},
32+
}));
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import {
4+
View,
5+
FlatList,
6+
TouchableOpacity,
7+
} from 'react-native';
8+
import {
9+
RkText,
10+
RkStyleSheet,
11+
} from 'react-native-ui-kitten';
12+
13+
export class CalendarScreen extends React.Component {
14+
static navigationOptions = {
15+
title: 'Calendars',
16+
};
17+
18+
static propTypes = {
19+
navigation: PropTypes.shape({
20+
navigate: PropTypes.func.isRequired,
21+
}).isRequired,
22+
};
23+
24+
static data = [
25+
{
26+
title: 'Base',
27+
description: "'Minimum code' implementation",
28+
route: 'BaseCalendar',
29+
},
30+
{
31+
title: 'Range',
32+
description: 'If you want to select date range',
33+
route: 'RangeCalendar',
34+
},
35+
{
36+
title: 'Bounding Month',
37+
description: 'No next month days at the end of the current',
38+
route: 'BoundingCalendar',
39+
},
40+
{
41+
title: 'Custom Day Cell',
42+
description: "Don't like default implementation?",
43+
route: 'CustomCalendar',
44+
},
45+
{
46+
title: 'Horizontal',
47+
description: 'Like vertical but horizontal',
48+
route: 'HorizontalCalendar',
49+
},
50+
];
51+
52+
getItemKey = (item, index) => index.toString();
53+
54+
onItemClick = (item) => {
55+
this.props.navigation.navigate(item.route);
56+
};
57+
58+
renderItem = ({ item }) => (
59+
<TouchableOpacity onPress={() => this.onItemClick(item)}>
60+
<View style={styles.componentRow}>
61+
<RkText rkType='header'>{item.title}</RkText>
62+
<RkText rkType='subtitle'>{item.description}</RkText>
63+
</View>
64+
</TouchableOpacity>
65+
);
66+
67+
render() {
68+
return (
69+
<View style={styles.container}>
70+
<RkText>
71+
{'RkCalendar is a component which allows user to select date or date range.' +
72+
' Check out some examples below prepared for you to see the power!'}
73+
</RkText>
74+
<View style={styles.descriptionSeparator} />
75+
<FlatList
76+
data={CalendarScreen.data}
77+
keyExtractor={this.getItemKey}
78+
renderItem={this.renderItem}
79+
/>
80+
</View>
81+
);
82+
}
83+
}
84+
85+
const styles = RkStyleSheet.create(theme => ({
86+
container: {
87+
flex: 1,
88+
paddingVertical: 8,
89+
paddingHorizontal: 16,
90+
backgroundColor: theme.colors.screen.base,
91+
},
92+
descriptionSeparator: {
93+
height: 2,
94+
marginVertical: 8,
95+
backgroundColor: theme.colors.border.base,
96+
},
97+
componentRow: {
98+
paddingVertical: 8,
99+
justifyContent: 'space-between',
100+
},
101+
}));
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import React from 'react';
2+
import {
3+
View,
4+
Text,
5+
} from 'react-native';
6+
import {
7+
RkCalendar,
8+
RkStyleSheet,
9+
} from 'react-native-ui-kitten';
10+
11+
export class CustomCalendarScreen extends React.Component {
12+
static navigationOptions = {
13+
title: 'Custom Calendar',
14+
};
15+
16+
getContentStyle = (state) => ({
17+
container: {
18+
base: state.isToday ? [styles.dayContainer, styles.dayContainerToday] : styles.dayContainer,
19+
selected: state.isSelected ? styles.dayContainerSelected : null,
20+
highlighted: state.isHighlighted ? styles.dayContainerHighlighted : null,
21+
disabled: state.isDisabled ? styles.dayContainerDisabled : null,
22+
},
23+
text: {
24+
base: state.isToday ? [styles.dayText, styles.dayTextToday] : styles.dayText,
25+
selected: state.isSelected ? styles.dayTextSelected : null,
26+
highlighted: state.isHighlighted ? styles.dayTextHighlighted : null,
27+
disabled: state.isDisabled ? styles.dayTextDisabled : null,
28+
},
29+
revenue: {
30+
fontSize: 12,
31+
},
32+
});
33+
34+
renderDay = (date, state) => {
35+
const { container, text, revenue } = this.getContentStyle(state);
36+
const revenueText = state.isEmpty ? '' : `${(date.getDate() + 100) * date.getDate()}$`;
37+
return (
38+
<View style={[container.base, container.selected, container.highlighted, container.disabled]}>
39+
<Text style={[text.base, text.selected, text.highlighted, text.disabled]}>
40+
{state.isEmpty ? '' : date.getDate()}
41+
</Text>
42+
<Text style={[text.base, text.selected, text.highlighted, text.disabled, revenue]}>
43+
{revenueText}
44+
</Text>
45+
</View>
46+
);
47+
};
48+
49+
render() {
50+
return (
51+
<View style={styles.container}>
52+
<RkCalendar
53+
min={new Date(2018, 0, 1)}
54+
max={new Date(2019, 0, 1)}
55+
renderDay={this.renderDay}
56+
/>
57+
</View>
58+
);
59+
}
60+
}
61+
62+
const styles = RkStyleSheet.create(theme => ({
63+
container: {
64+
flex: 1,
65+
backgroundColor: theme.colors.background,
66+
paddingHorizontal: 8,
67+
},
68+
dayContainer: {
69+
flex: 1,
70+
justifyContent: 'center',
71+
alignItems: 'center',
72+
borderRadius: 4,
73+
paddingVertical: 8,
74+
},
75+
dayContainerToday: {
76+
backgroundColor: theme.colors.highlight,
77+
},
78+
dayContainerSelected: {
79+
backgroundColor: theme.colors.button.primary,
80+
borderRadius: 4,
81+
},
82+
dayContainerHighlighted: {
83+
backgroundColor: theme.colors.button.primary,
84+
opacity: 0.25,
85+
borderRadius: 0,
86+
},
87+
dayContainerDisabled: {
88+
opacity: 0.25,
89+
},
90+
dayText: {
91+
fontSize: theme.fonts.sizes.large,
92+
color: theme.colors.text.base,
93+
fontWeight: '300',
94+
},
95+
dayTextToday: {
96+
fontWeight: 'bold',
97+
},
98+
dayTextSelected: {
99+
color: theme.colors.text.inverse,
100+
fontWeight: 'bold',
101+
},
102+
dayTextHighlighted: {
103+
fontWeight: '300',
104+
},
105+
dayTextDisabled: {
106+
},
107+
}));

0 commit comments

Comments
 (0)