diff --git a/ios/WidgetsShowcase.xcodeproj/project.pbxproj b/ios/WidgetsShowcase.xcodeproj/project.pbxproj
index 65f3c6a..d884bfb 100644
--- a/ios/WidgetsShowcase.xcodeproj/project.pbxproj
+++ b/ios/WidgetsShowcase.xcodeproj/project.pbxproj
@@ -1325,6 +1325,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = WidgetsShowcase;
+ TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
@@ -1348,6 +1349,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = WidgetsShowcase;
+ TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
diff --git a/packages/Calendar/src/Calendar/CalendarView.js b/packages/Calendar/src/Calendar/CalendarView.js
new file mode 100644
index 0000000..f140ad0
--- /dev/null
+++ b/packages/Calendar/src/Calendar/CalendarView.js
@@ -0,0 +1,107 @@
+// @flow
+import React, { useContext, useCallback } from 'react';
+import { View, StyleSheet } from 'react-native';
+import Month from './Month';
+
+import CalendarContext from '../common/CalendarContext';
+import { primaryColor } from '../theme';
+import Header from '../common/Header';
+
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ padding: 5,
+ },
+ clearTextContainer: {
+ marginLeft: 15,
+ },
+ clearText: {
+ fontSize: 14,
+ color: primaryColor,
+ },
+ row: {
+ flexDirection: 'row',
+ },
+});
+
+type Props = {
+ renderDate: (date: Date) => React.Node,
+ setValue: number => void,
+ value: ?Date,
+ setView: React.Node => void,
+ type: 'multi' | 'range' | 'single',
+}
+
+function dateRange(date1, date2) {
+ const diffTime = date2.getTime() - date1.getTime();
+ const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
+ const startDate = diffDays < 0 ? date2 : date1;
+ const dates = Array(Math.abs(diffDays)).fill(new Date(startDate)).map(m => new Date(m.setDate(m.getDate() + 1)));
+ return [startDate, ...dates];
+}
+
+function CalendarView({
+ renderDate, setValue, value, setView, type,
+}: Props) {
+ const [months, setMonths] = useContext(CalendarContext);
+
+ const shift = useCallback((val) => {
+ setMonths(mnths => mnths.map(d => new Date(
+ d.getFullYear(),
+ d.getMonth() + val,
+ 1
+ )));
+ }, []);
+
+ const selectDate = useCallback((d, long) => {
+ setValue((prev) => {
+ if (type === 'multi') {
+ if (Array.isArray(prev)) {
+ // logic to remove the date if already Selected
+ const isAlreadySelected = prev.filter(dates => dates.toDateString() === d.toDateString());
+ return isAlreadySelected.length > 0
+ ? [...prev.filter(dates => dates.toDateString() !== d.toDateString())]
+ : [...prev, d];
+ }
+ if (long) {
+ return prev ? [prev, d] : [d];
+ }
+ } else if (type === 'range') {
+ if (Array.isArray(prev)) {
+ return d;
+ }
+ if (prev) {
+ return dateRange(prev, d);
+ }
+ return d;
+ }
+ return d;
+ });
+ }, []);
+
+ function clearSelect() {
+ setValue(null);
+ }
+
+ clearSelect.title = 'Clear';
+ return (
+ <>
+ {months.map(month => (
+
+
+
+ ))}
+
+ >
+ );
+}
+
+
+export default CalendarView;
diff --git a/packages/Calendar/src/Day.js b/packages/Calendar/src/Calendar/Day.js
similarity index 70%
rename from packages/Calendar/src/Day.js
rename to packages/Calendar/src/Calendar/Day.js
index f9ee445..13cd230 100644
--- a/packages/Calendar/src/Day.js
+++ b/packages/Calendar/src/Calendar/Day.js
@@ -1,14 +1,8 @@
// @flow
import React from 'react';
import { View, TouchableOpacity, Text, StyleSheet } from 'react-native';
-import { getTheme } from '@sharingapples/theme';
+import { textColor, backgroundColor, primaryFontColor, primaryColor, disabledFontColor } from '../theme';
-const theme = getTheme();
-const calendarTheme = theme.onCalendar || theme;
-const textColor = calendarTheme.onBackground;
-const backgroundColor = calendarTheme.background;
-const primaryFontColor = theme.onPrimary;
-const disabledFontColor = theme.disabled;
const styles = StyleSheet.create({
container: {
@@ -16,11 +10,13 @@ const styles = StyleSheet.create({
alignItems: 'center',
paddingHorizontal: 3,
paddingVertical: 3,
- borderLeftWidth: 1,
- borderRightWidth: 1,
- borderTopWidth: 1,
- borderBottomWidth: 1,
- margin: -1,
+ borderWidth: StyleSheet.hairlineWidth,
+ margin: -StyleSheet.hairlineWidth,
+ // because of inconsistency in android for border each has to be defined
+ borderLeftColor: 'transparent',
+ borderRightColor: 'transparent',
+ borderTopColor: 'transparent',
+ borderBottomColor: 'transparent',
},
textContainer: {
paddingHorizontal: 6,
@@ -31,6 +27,9 @@ const styles = StyleSheet.create({
width: 30,
height: 30,
},
+ text: {
+ fontSize: 14,
+ },
});
type Props = {
@@ -55,10 +54,9 @@ function Day({
const dateObj = new Date(date);
const isCurrentMonth = currentMonth === dateObj.getMonth();
const isToday = dateObj.toDateString() === new Date().toDateString();
-
return (
{
// stack this to selected date
selectDate(dateObj, true);
@@ -70,15 +68,14 @@ function Day({
>
{dateObj.getDate()}
diff --git a/packages/Calendar/src/Calendar/Month.js b/packages/Calendar/src/Calendar/Month.js
new file mode 100644
index 0000000..4b8aa3f
--- /dev/null
+++ b/packages/Calendar/src/Calendar/Month.js
@@ -0,0 +1,104 @@
+// @flow
+import React from 'react';
+import { View, StyleSheet, TouchableOpacity, Text } from 'react-native';
+import Week from './Week';
+import MonthSelection from '../MonthSelection';
+import YearSelection from '../YearSelection';
+import { WEEK_DAYS } from '../common/util';
+import { textColor } from '../theme';
+
+type Props = {
+ date: Date,
+ setView: React.Node => void,
+}
+
+
+const styles = StyleSheet.create({
+ header: {
+ flexDirection: 'row',
+ justifyContent: 'center',
+ paddingVertical: 5,
+ },
+ dateText: {
+ fontSize: 14,
+ color: textColor,
+ },
+ nav: {
+ paddingHorizontal: 5,
+ },
+ navText: {
+ fontSize: 14,
+ },
+ daysContainer: {
+ width: '100%',
+ flexDirection: 'row',
+ marginTop: 5,
+ paddingVertical: 5,
+ marginBottom: 5,
+ borderBottomColor: textColor,
+ borderBottomWidth: StyleSheet.hairlineWidth,
+ },
+ day: {
+ flex: 1,
+ alignItems: 'center',
+ },
+ dayText: {
+ fontSize: 14,
+ color: textColor,
+ },
+});
+
+const NUM_OF_WEEKS = 6;
+const WEEK_DIFF = 7 * 86400 * 1000;
+
+function getStartOfMonth(date) {
+ const first = new Date(date.getFullYear(), date.getMonth(), 1);
+ return first.getTime() - first.getDay() * 86400 * 1000;
+}
+
+function Month({ date, setView, ...other }: Props) {
+ const start = getStartOfMonth(date);
+ const dateString = date.toString();
+ const month = dateString.substr(4, 3);
+ const year = dateString.substr(11, 4);
+ const weeks = new Array(NUM_OF_WEEKS).fill(null).map((c, i) => start + i * WEEK_DIFF);
+ return (
+ <>
+
+
+ setView(() => MonthSelection)}
+ style={styles.nav}
+ >
+ {month}
+
+ setView(() => YearSelection)}
+ style={styles.nav}
+ >
+ {year}
+
+
+
+
+ {WEEK_DAYS.map(d => (
+
+ {d}
+
+ ))}
+
+
+
+ {weeks.map(week => (
+
+ ))}
+ >
+ );
+}
+
+export default Month;
diff --git a/packages/Calendar/src/Week.js b/packages/Calendar/src/Calendar/Week.js
similarity index 93%
rename from packages/Calendar/src/Week.js
rename to packages/Calendar/src/Calendar/Week.js
index c793905..8337432 100644
--- a/packages/Calendar/src/Week.js
+++ b/packages/Calendar/src/Calendar/Week.js
@@ -2,7 +2,7 @@
import React from 'react';
import { View, StyleSheet } from 'react-native';
import Day from './Day';
-import { getDateBorderStyle, DAY_DIFF } from './util';
+import { getDateBorderStyle, DAY_DIFF } from '../common/util';
const styles = StyleSheet.create({
container: {
diff --git a/packages/Calendar/src/Calendar/index.js b/packages/Calendar/src/Calendar/index.js
new file mode 100644
index 0000000..da70759
--- /dev/null
+++ b/packages/Calendar/src/Calendar/index.js
@@ -0,0 +1,3 @@
+import CalendarView from './CalendarView';
+
+export default CalendarView;
diff --git a/packages/Calendar/src/Header.js b/packages/Calendar/src/Header.js
deleted file mode 100644
index 6cfc9ff..0000000
--- a/packages/Calendar/src/Header.js
+++ /dev/null
@@ -1,123 +0,0 @@
-// @flow
-import React from 'react';
-import { View, Text, Image, StyleSheet, TouchableWithoutFeedback, TouchableOpacity } from 'react-native';
-import { getTheme } from '@sharingapples/theme';
-import right from './assets/right.png';
-import left from './assets/left.png';
-
-const theme = getTheme();
-const calendarTheme = theme.onCalendar || theme;
-const textColor = calendarTheme.onBackground;
-const primaryColor = calendarTheme.primary;
-
-
-const styles = StyleSheet.create({
- container: {
- justifyContent: 'space-between',
- flexDirection: 'row',
- paddingBottom: 5,
- },
- titleContainer: {
- flex: 1,
- alignItems: 'center',
- flexDirection: 'row',
- justifyContent: 'center',
- },
- dateText: {
- fontSize: 16,
- color: textColor,
- fontWeight: 'bold',
- },
- clearTextContainer: {
- marginLeft: 15,
- },
- clearText: {
- fontSize: 14,
- color: primaryColor,
- },
- dayContainer: {
- flexDirection: 'row',
- width: '100%',
- marginTop: 3,
- borderBottomColor: theme.colorDisabled,
- paddingBottom: 5,
- borderBottomWidth: StyleSheet.hairlineWidth,
- marginBottom: 5,
- },
- dayText: {
- flex: 1,
- fontSize: 12,
- color: textColor,
- textAlign: 'center',
- },
- left: {
- position: 'absolute',
- left: 0,
- },
- right: {
- position: 'absolute',
- right: 0,
- },
- icon: {
- paddingLeft: 10,
- paddingRight: 10,
- tintColor: textColor,
- },
-});
-
-type Props = {
- date: {},
- prevMonth: boolean,
- nextMonth: boolean,
- multiple: boolean,
- clearSelection: boolean => void,
- shiftMonth: number => void,
-}
-
-const WEEK_DAYS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
-
-function Header({ date, prevMonth, nextMonth, multiple, shiftMonth, clearSelection }: Props) {
- const dateString = date.toString();
- const month = dateString.substr(4, 3);
- const year = dateString.substr(11, 4);
- return (
- <>
-
-
-
- {month} {year}
-
- {multiple && (
- clearSelection(null)}
- >
- Clear Selection
-
- )}
-
- {prevMonth && (
-
- shiftMonth(-1)}>
-
-
-
- )}
-
- {nextMonth && (
-
- shiftMonth(1)}>
-
-
-
- )}
-
-
- {WEEK_DAYS.map(d => (
- {d}))}
-
- >
- );
-}
-
-export default React.memo(Header);
diff --git a/packages/Calendar/src/Month.js b/packages/Calendar/src/Month.js
deleted file mode 100644
index b43f5a2..0000000
--- a/packages/Calendar/src/Month.js
+++ /dev/null
@@ -1,34 +0,0 @@
-// @flow
-import React from 'react';
-import Week from './Week';
-
-type Props = {
- month: number,
- onSelect: (date: Date) => void,
- start: number,
- selectedDate: Date,
-}
-
-const NUM_OF_WEEKS = 5;
-const WEEK_DIFF = 7 * 86400 * 1000;
-
-function getStartOfMonth(date) {
- const first = new Date(date.getFullYear(), date.getMonth(), 1);
- return first.getTime() - first.getDay() * 86400 * 1000;
-}
-
-
-function Month({ date, ...other }: Props) {
- const start = getStartOfMonth(date);
- const weeks = new Array(NUM_OF_WEEKS).fill(null).map((c, i) => start + i * WEEK_DIFF);
- return weeks.map(week => (
-
- ));
-}
-
-export default Month;
diff --git a/packages/Calendar/src/MonthSelection/MonthView.js b/packages/Calendar/src/MonthSelection/MonthView.js
new file mode 100644
index 0000000..70de2c4
--- /dev/null
+++ b/packages/Calendar/src/MonthSelection/MonthView.js
@@ -0,0 +1,121 @@
+// @flow
+import React, { useState, useCallback } from 'react';
+import { View, StyleSheet, TouchableOpacity, Text } from 'react-native';
+
+import { textColor } from '../theme';
+import { ALL_MONTHS } from '../common/util';
+import YearView from '../YearSelection';
+import Header from '../common/Header';
+
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ },
+ header: {
+ width: '100%',
+ alignItems: 'center',
+ padding: 5,
+ },
+ dateText: {
+ fontSize: 14,
+ color: textColor,
+ },
+ nav: {
+ padding: 5,
+ },
+ month: {
+ flex: 1,
+ paddingVertical: 12,
+ alignItems: 'center',
+ },
+ row: {
+ flexDirection: 'row',
+ },
+ navBar: {
+ width: '100%',
+ position: 'absolute',
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ paddingHorizontal: 16,
+ paddingVertical: 10,
+ },
+});
+
+function renderHeader(year, setView) {
+ return (
+
+ setView(() => YearView)}
+ >
+
+ {year}
+
+
+
+ );
+}
+
+function renderAllMonth(year, selectMonth) {
+ const months = [];
+ for (let i = 0; i < 3; i += 1) {
+ const row = [0, 1, 2, 3].map((m) => {
+ const month = m + 4 * i;
+ return (
+ selectMonth(year, month)}
+ >
+ {ALL_MONTHS[month]}
+
+ );
+ });
+ months.push({row});
+ }
+ return months;
+}
+
+type Props = {
+ setView: React.Node => void,
+ value: Date | Array,
+}
+
+function MonthView({ setView, value }: Props) {
+ const [months, setMonths] = useState(value);
+
+ const shift = useCallback((val) => {
+ setMonths(mnths => mnths.map(d => new Date(
+ d.getFullYear() + val,
+ d.getMonth(),
+ 1
+ )));
+ }, []);
+
+ const selectMonth = useCallback((year, month) => {
+ setMonths(mnths => mnths.map((d, idx) => new Date(year, month + idx, 1)));
+ setView(() => null);
+ }, []);
+
+
+ function back() {
+ setView(() => null);
+ }
+
+ back.title = 'Back';
+
+ return (
+ <>
+ {months.map((month, idx) => (
+
+ {renderHeader(month.getFullYear() + idx, setView)}
+ {renderAllMonth(month.getFullYear() + idx, selectMonth)}
+
+ ))}
+
+ >
+ );
+}
+
+export default MonthView;
diff --git a/packages/Calendar/src/MonthSelection/index.js b/packages/Calendar/src/MonthSelection/index.js
new file mode 100644
index 0000000..cf01128
--- /dev/null
+++ b/packages/Calendar/src/MonthSelection/index.js
@@ -0,0 +1,3 @@
+import MonthView from './MonthView';
+
+export default MonthView;
diff --git a/packages/Calendar/src/YearSelection/YearView.js b/packages/Calendar/src/YearSelection/YearView.js
new file mode 100644
index 0000000..41d8082
--- /dev/null
+++ b/packages/Calendar/src/YearSelection/YearView.js
@@ -0,0 +1,120 @@
+// @flow
+import React, { useCallback, useState } from 'react';
+import { View, StyleSheet, TouchableOpacity, Text } from 'react-native';
+
+import { textColor } from '../theme';
+import MonthSelection from '../MonthSelection';
+import Header from '../common/Header';
+
+const YEARS_DIFF = 20;
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ },
+ dateText: {
+ fontSize: 14,
+ color: textColor,
+ },
+ header: {
+ alignItems: 'center',
+ width: '100%',
+ paddingVertical: 10,
+ },
+ year: {
+ flex: 1,
+ paddingVertical: 12,
+ alignItems: 'center',
+ },
+ row: {
+ flexDirection: 'row',
+ },
+ nav: {
+ padding: 5,
+ },
+ navBar: {
+ width: '100%',
+ position: 'absolute',
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ paddingHorizontal: 16,
+ paddingVertical: 10,
+ },
+});
+
+function renderHeaderTitle() {
+ return (
+ <>
+
+
+ Years
+
+
+ >
+ );
+}
+
+
+function renderAllYears(initalYear, selectYear) {
+ const years = [];
+ for (let i = 0; i < 5; i += 1) {
+ const yearStart = initalYear + i * 1;
+ const row = [0, 1, 2, 3].map((y) => {
+ const year = yearStart + 5 * y;
+ return (
+ selectYear(year)}
+ >
+ {year}
+
+ );
+ });
+ years.push({row});
+ }
+ return years;
+}
+
+type Props = {
+ setView: React.Node => void,
+ value: Date | Array,
+}
+
+function YearView({ setView, value }: Props) {
+ const [months, setMonths] = useState(value);
+
+ const shift = useCallback((val) => {
+ setMonths(mnths => mnths.map(d => new Date(
+ d.getFullYear() + val * YEARS_DIFF,
+ d.getMonth(),
+ 1
+ )));
+ }, []);
+
+ const selectYear = useCallback((year) => {
+ setMonths(mnths => mnths.map((d, idx) => new Date(year + idx, d.getMonth(), 1)));
+ setView(() => MonthSelection);
+ }, [setMonths, setView]);
+
+ function back() {
+ setView(() => null);
+ }
+
+ back.title = 'Back';
+
+
+ return (
+ <>
+ {months.map((month, idx) => (
+
+ {renderHeaderTitle()}
+ {renderAllYears(month.getFullYear() + idx * YEARS_DIFF, selectYear)}
+
+ ))}
+
+ >
+ );
+}
+
+export default YearView;
diff --git a/packages/Calendar/src/YearSelection/index.js b/packages/Calendar/src/YearSelection/index.js
new file mode 100644
index 0000000..fccb5f1
--- /dev/null
+++ b/packages/Calendar/src/YearSelection/index.js
@@ -0,0 +1,3 @@
+import YearView from './YearView';
+
+export default YearView;
diff --git a/packages/Calendar/src/common/Button.js b/packages/Calendar/src/common/Button.js
new file mode 100644
index 0000000..6f27cd4
--- /dev/null
+++ b/packages/Calendar/src/common/Button.js
@@ -0,0 +1,30 @@
+// @flow
+import React from 'react';
+import { TouchableOpacity, Text, StyleSheet } from 'react-native';
+import { primaryColor } from '../theme';
+
+type Props = {
+ onPress: number => void,
+ title: string,
+}
+
+const styles = StyleSheet.create({
+ container: {
+ paddingHorizontal: 5,
+ marginRight: 10,
+ },
+ text: {
+ color: primaryColor,
+ },
+});
+
+const Button = ({ onPress, title }: Props) => (
+ onPress()}
+ >
+ {title}
+
+);
+
+export default Button;
diff --git a/packages/Calendar/src/common/CalendarContext.js b/packages/Calendar/src/common/CalendarContext.js
new file mode 100644
index 0000000..6353dc0
--- /dev/null
+++ b/packages/Calendar/src/common/CalendarContext.js
@@ -0,0 +1,3 @@
+import React from 'react';
+
+export default React.createContext();
diff --git a/packages/Calendar/src/common/Header.js b/packages/Calendar/src/common/Header.js
new file mode 100644
index 0000000..714f39e
--- /dev/null
+++ b/packages/Calendar/src/common/Header.js
@@ -0,0 +1,38 @@
+// @flow
+import React from 'react';
+import { View, StyleSheet } from 'react-native';
+import IconButton from './IconButton';
+import Button from './Button';
+import left from '../assets/left.png';
+import right from '../assets/right.png';
+
+const styles = StyleSheet.create({
+ container: {
+ width: '100%',
+ position: 'absolute',
+ flexDirection: 'row',
+ paddingHorizontal: 16,
+ paddingVertical: 10,
+ justifyContent: 'space-between',
+ },
+ row: {
+ flexDirection: 'row',
+ },
+});
+
+type Props = {
+ shift: number => void,
+ action: () => void,
+}
+
+const Header = ({ shift, action }: Props) => (
+
+ shift(-1)} />
+
+ {action && }
+ shift(1)} />
+
+
+);
+
+export default Header;
diff --git a/packages/Calendar/src/common/IconButton.js b/packages/Calendar/src/common/IconButton.js
new file mode 100644
index 0000000..3565907
--- /dev/null
+++ b/packages/Calendar/src/common/IconButton.js
@@ -0,0 +1,19 @@
+// @flow
+import React from 'react';
+import { TouchableOpacity, Image } from 'react-native';
+
+
+type Props = {
+ onPress: number => void,
+ icon: number,
+}
+
+const IconButton = ({ onPress, icon }: Props) => (
+ onPress(-1)}
+ >
+
+
+);
+
+export default IconButton;
diff --git a/packages/Calendar/src/common/util.js b/packages/Calendar/src/common/util.js
new file mode 100644
index 0000000..62170cc
--- /dev/null
+++ b/packages/Calendar/src/common/util.js
@@ -0,0 +1,75 @@
+import { primaryColor } from '../theme';
+
+/* eslint-disable no-bitwise */
+
+export const DAY_DIFF = 86400 * 1000;
+export const SEVEN_DAYS = 7;
+export const SINGLE_DAY = 1;
+
+export const WEEK_DAYS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
+export const ALL_MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sept', 'Oct', 'Nov', 'Dec'];
+
+const borderStyles = Array(16).fill(null).map((n, idx) => ({
+ borderTopColor: idx & 1 ? 'transparent' : primaryColor,
+ borderRightColor: idx & 2 ? 'transparent' : primaryColor,
+ borderBottomColor: idx & 4 ? 'transparent' : primaryColor,
+ borderLeftColor: idx & 8 ? 'transparent' : primaryColor,
+}));
+
+
+export function getMonthCount({ width }, date) {
+ const value = Array.isArray(date) ? date[0] : date;
+ return width > 560
+ ? [value, new Date(value.getFullYear(), value.getMonth() + 1)] : [value];
+}
+
+const cache = {};
+
+function memoize(dep) {
+ if (cache[dep]) {
+ return cache[dep];
+ }
+ cache[dep] = dep.reduce((acc, cur) => {
+ acc[cur.toDateString()] = true;
+ return acc;
+ }, {});
+ return cache[dep];
+}
+
+export function isDate(date) {
+ return date instanceof Date;
+}
+
+function getDateString(date, diff) {
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate() + diff).toDateString();
+}
+
+export function getDateBorderStyle(date, selectedDates) {
+ if (!selectedDates) {
+ return undefined;
+ }
+
+ if (isDate(selectedDates)) {
+ return selectedDates.toDateString() === date.toDateString() ? borderStyles[0] : undefined;
+ }
+
+ const allDates = memoize(selectedDates);
+
+ const currentDateString = date.toDateString();
+ if (!allDates[currentDateString]) {
+ return undefined;
+ }
+
+ const prevWeek = getDateString(date, -SEVEN_DAYS);
+ const nextWeek = getDateString(date, SEVEN_DAYS);
+ const nextDay = getDateString(date, SINGLE_DAY);
+ const prevDay = getDateString(date, -SINGLE_DAY);
+
+ const bit0 = allDates[prevWeek] ? 1 : 0;
+ const bit1 = allDates[nextDay] ? 2 : 0;
+ const bit2 = allDates[nextWeek] ? 4 : 0;
+ const bit3 = allDates[prevDay] ? 8 : 0;
+
+ const borderStyleIndex = bit0 | bit1 | bit2 | bit3;
+ return borderStyles[borderStyleIndex];
+}
diff --git a/packages/Calendar/src/index.js b/packages/Calendar/src/index.js
index a0820d3..8994c4d 100644
--- a/packages/Calendar/src/index.js
+++ b/packages/Calendar/src/index.js
@@ -1,94 +1,61 @@
// @flow
import React, { useState, useCallback } from 'react';
-import { View, StyleSheet, Dimensions } from 'react-native';
-import { getTheme } from '@sharingapples/theme';
-import Header from './Header';
-import Month from './Month';
+import { Dimensions, View, StyleSheet } from 'react-native';
+import CalendarView from './Calendar';
-const theme = getTheme();
-const calendarTheme = theme.onCalendar || theme;
+import CalendarContext from './common/CalendarContext';
+import { getMonthCount } from './common/util';
+import { backgroundColor } from './theme';
+
+type Props = {
+ value: Date | Array
+}
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
- backgroundColor: calendarTheme.background,
+ backgroundColor,
+ },
+ navBar: {
+ width: '100%',
+ position: 'absolute',
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ },
+ row: {
+ flexDirection: 'row',
+ },
+ view: {
+ position: 'absolute',
+ backgroundColor: 'white',
+ width: '100%',
+ height: '100%',
+ flexDirection: 'row',
},
});
-function getMonthCount({ width }, value) {
- const date = Array.isArray(value) ? value[0] : value;
- return width > 400
- ? [date, new Date(date.getFullYear(), date.getMonth() + 1)] : [date];
-}
-
-type Props = {
- renderDate: (date: Date) => React.Node,
- setValue: number => void,
- value: ?Date,
-}
-
-function Calendar({
- renderDate, setValue, value,
-}: Props) {
+function Calendar({ value, ...other }: Props) {
const [months, setMonths] = useState(() => getMonthCount(Dimensions.get('screen'), value));
+ const [CurrentView, setView] = useState(() => null);
const handleLayout = useCallback((e) => {
const { layout } = e.nativeEvent;
setMonths(mnths => getMonthCount(layout, mnths));
- }, [setMonths]);
-
-
- const shiftMonth = useCallback((shift) => {
- setMonths(mnths => mnths.map(d => new Date(d.getFullYear(), d.getMonth() + shift, 1)));
- }, [setMonths]);
-
- const selectDate = useCallback((d, long) => {
- setValue((prev) => {
- if (Array.isArray(prev)) {
- // called if clearSelect is pressed
- if (!d) {
- return null;
- }
- // logic to remove the date if already Selected
- const isAlreadySelected = prev.filter(dates => dates.toDateString() === d.toDateString());
- return isAlreadySelected.length > 0
- ? [...prev.filter(dates => dates.toDateString() !== d.toDateString())]
- : [...prev, d];
- }
- if (long) {
- return prev ? [prev, d] : [d];
- }
- return d;
- });
- }, [setValue]);
-
-
- const first = 0;
- const last = months.length - 1;
+ }, []);
return (
-
- {months.map((month, idx) => (
-
-
-
-
- ))}
-
+
+
+
+ {CurrentView
+ && (
+
+
+
+ )}
+
+
);
}
-
export default Calendar;
diff --git a/packages/Calendar/src/theme.js b/packages/Calendar/src/theme.js
new file mode 100644
index 0000000..e3d818a
--- /dev/null
+++ b/packages/Calendar/src/theme.js
@@ -0,0 +1,9 @@
+import { getTheme } from '@sharingapples/theme';
+
+export const theme = getTheme();
+export const calendarTheme = theme.Calendar || theme;
+export const textColor = calendarTheme.onBackground;
+export const backgroundColor = calendarTheme.background;
+export const primaryFontColor = calendarTheme.onPrimary;
+export const primaryColor = calendarTheme.primary;
+export const disabledFontColor = calendarTheme.disabled;
diff --git a/packages/Calendar/src/util.js b/packages/Calendar/src/util.js
index cd95bc6..5a82138 100644
--- a/packages/Calendar/src/util.js
+++ b/packages/Calendar/src/util.js
@@ -34,6 +34,10 @@ export function isDate(date) {
return date instanceof Date;
}
+export function generateYears(year) {
+ return Array(16).fill(0).map((m, idx) => year + idx);
+}
+
function getDateString(date, diff) {
return new Date(date.getFullYear(), date.getMonth(), date.getDate() + diff).toDateString();
diff --git a/packages/Form/src/Editor.js b/packages/Form/src/Editor.js
index 1dee8d7..b8c231f 100644
--- a/packages/Form/src/Editor.js
+++ b/packages/Form/src/Editor.js
@@ -56,8 +56,8 @@ function createManager(initialState, parent, onChange, onSubmit) {
mappedSubscriptions.forEach(([listener, mapper]) => listener(mapper(newState)));
// Trigger the on change event
- if (!requiresSubmit && onChange) {
- onChange(newState);
+ if (!requiresSubmit) {
+ if (onChange) onChange(newState);
}
},
subscribe: (name: string | () => any, listener: (any) => void) => {
@@ -113,6 +113,7 @@ function createManager(initialState, parent, onChange, onSubmit) {
},
submit: async () => {
// Run all the validators
+
try {
formState = FORM_STATE_BUSY;
const res = await Promise.all(validators.map(v => v.confirm()));
diff --git a/packages/Wizard/form/FormPage.js b/packages/Wizard/form/FormPage.js
index cf4599b..41328af 100644
--- a/packages/Wizard/form/FormPage.js
+++ b/packages/Wizard/form/FormPage.js
@@ -3,10 +3,9 @@ import React from 'react';
import { View, Text, ScrollView, TouchableOpacity, StyleSheet } from 'react-native';
import { Group, useFormSubmit } from '@sharingapples/form';
import { getTheme } from '@sharingapples/theme';
-import { StatusBar, RootView, SafePadding } from '@sharingapples/widgets';
+import { StatusBar } from '@sharingapples/widgets';
import { useWizard } from '../src';
-
const theme = getTheme();
const componentTheme = theme.Wizard || theme;
const { backgroundColor } = componentTheme;
@@ -16,7 +15,7 @@ const styles = StyleSheet.create({
footer: {
flexDirection: 'row',
justifyContent: 'space-between',
- marginBottom: SafePadding.bottom / 2,
+ padding: 16,
},
text: {
fontSize: 14,
@@ -55,11 +54,12 @@ function Submit({ title }: SubmitProps) {
}
-function FormPage({ title, prevTitle, nextTitle, group, style, ...other }: Props) {
+function FormPage({ title, prevTitle, nextTitle, group, ...other }: Props) {
const { prev, next } = useWizard();
+
return (
-
- {!!title && {title}}
+ <>
+ {!!title && }
: }
-
+ >
);
}
diff --git a/packages/Wizard/package.json b/packages/Wizard/package.json
index adf4808..2be3b72 100644
--- a/packages/Wizard/package.json
+++ b/packages/Wizard/package.json
@@ -8,6 +8,9 @@
"publishConfig": {
"access": "public"
},
+ "dependencies": {
+ "@sharingapples/animation": "^1.0.12"
+ },
"peerDependencies": {
"@sharingapples/form": "^1.0.12",
"@sharingapples/theme": "^1.0.3",
diff --git a/packages/Wizard/src/index.js b/packages/Wizard/src/index.js
index dbbc37c..6cae097 100644
--- a/packages/Wizard/src/index.js
+++ b/packages/Wizard/src/index.js
@@ -1,5 +1,7 @@
// @flow
-import React, { useState, useContext } from 'react';
+import React, { useState, useContext, useCallback, useRef } from 'react';
+import { View, StyleSheet } from 'react-native';
+import { TransitionView, useTransitionState } from '@sharingapples/animation';
const WizardContext = React.createContext();
@@ -13,19 +15,64 @@ type Props = {
onComplete: () => any,
}
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ },
+});
+
+
function Wizard({ children, start, onComplete }: Props) {
+ const width = useRef(0);
const [page, setPage] = useState(Number(start));
+ const controller = useTransitionState(page);
+
const pages = React.Children.toArray(children);
- const next = page === (pages.length - 1) ? onComplete : () => setPage(p => p + 1);
- const prev = () => setPage(p => p - 1);
+ const next = useCallback(() => {
+ if (page === pages.length - 1) {
+ onComplete();
+ } else {
+ setPage(p => p + 1);
+ }
+ }, [page, setPage]);
- const currentPage = pages[page];
- const context = { next, prev, page };
+ const prev = useCallback(() => {
+ setPage(p => p - 1);
+ }, [setPage]);
+
+ const wizAnimStyle = useCallback((driver, state, otherState) => ({
+ ...StyleSheet.absoluteFillObject,
+ transform: [
+ {
+ translateX: driver.interpolate({
+ inputRange: [0, 1],
+ // $FlowFixMe value is initialized to zero on useRef
+ outputRange: [Math.sign(state - otherState) * width.current, 0],
+ }),
+ },
+ ],
+ }), []);
+
+ const calcWidth = (e) => { width.current = e.nativeEvent.layout.width; }
+ const context = { next, prev, page };
return (
-
- {currentPage}
-
+
+
+ {pages.map((p, index) => (
+
+ {p}
+
+ ))
+ }
+
+
);
}
diff --git a/showcase/screens/Calendar.js b/showcase/screens/Calendar.js
index 65ccf20..5ee997f 100644
--- a/showcase/screens/Calendar.js
+++ b/showcase/screens/Calendar.js
@@ -8,7 +8,7 @@ export default function Calendar() {
return (
Calendar
-
+
);
}
diff --git a/showcase/screens/Wizard/PageWithForm.js b/showcase/screens/Wizard/PageWithForm.js
index c5488ea..120e052 100644
--- a/showcase/screens/Wizard/PageWithForm.js
+++ b/showcase/screens/Wizard/PageWithForm.js
@@ -1,17 +1,14 @@
import React from 'react';
import { View, TextInput } from 'react-native';
import FormPage from '@sharingapples/wizard/form/FormPage';
-import { Form } from '@sharingapples/form';
import LineInput from '../Form/LineInput';
-function SecondPage() {
+function PageWithForm() {
return (
-
+
+
+
);
}
-export default SecondPage;
+export default PageWithForm;
diff --git a/showcase/screens/Wizard/index.js b/showcase/screens/Wizard/index.js
index 46e6d21..3f50565 100644
--- a/showcase/screens/Wizard/index.js
+++ b/showcase/screens/Wizard/index.js
@@ -1,14 +1,17 @@
import React from 'react';
import Wizard from '@sharingapples/wizard';
+import { Form } from '@sharingapples/form';
import PageWithNoForm from './PageWithNoForm';
import PageWithForm from './PageWithForm';
function WizardShowCase() {
return (
- alert('This was last page in wizard')}>
-
-
-
+
);
}