├── src
├── App.css
├── index.js
├── global
│ └── helpers
│ │ └── hexToRgb.js
├── index.css
├── App.js
└── components
│ ├── DatePicker.module.css
│ ├── DatePicker.js
│ ├── MonthView.js
│ └── DateView.js
├── .idea
├── misc.xml
├── vcs.xml
├── modules.xml
├── react-horizontal-datepicker.iml
├── $CACHE_FILE$
└── inspectionProfiles
│ └── Project_Default.xml
├── public
└── index.html
├── dist
├── global
│ └── helpers
│ │ └── hexToRgb.js
└── components
│ ├── DatePicker.module.css
│ ├── DatePicker.js
│ ├── MonthView.js
│ └── DateView.js
├── .gitignore
├── LICENSE
├── README.md
└── package.json
/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | padding: 15px;
3 | background: white;
4 | }
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App';
5 |
6 | ReactDOM.render(, document.getElementById('root'));
7 |
8 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Strip
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/dist/global/helpers/hexToRgb.js:
--------------------------------------------------------------------------------
1 | export default function hexToRgb(hex) {
2 | var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
3 | return result ? "rgb(" + parseInt(result[1], 16) + ',' + parseInt(result[2], 16) + ',' + parseInt(result[3], 16) + ")" : null;
4 | }
--------------------------------------------------------------------------------
/src/global/helpers/hexToRgb.js:
--------------------------------------------------------------------------------
1 | export default function hexToRgb(hex) {
2 | var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
3 | return result ? "rgb("
4 | + parseInt(result[1], 16) + ','
5 | + parseInt(result[2], 16) + ','
6 | + parseInt(result[3], 16) + ")" : null;
7 | }
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/react-horizontal-datepicker.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 | package-lock.json
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 | /.idea/
25 | /.idea/workspace.xml
26 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './App.css';
3 | import { DatePicker } from "./components/DatePicker";
4 |
5 | function App() {
6 | const selectedDay = (val) =>{
7 | console.log(val)
8 | };
9 |
10 | const startDate = new Date(2010, 0, 1);
11 |
12 | return (
13 |
14 |
21 |
22 | );
23 | }
24 |
25 | export default App;
26 |
--------------------------------------------------------------------------------
/.idea/$CACHE_FILE$:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | CoffeeScript
12 |
13 |
14 | GeneralCoffeeScript
15 |
16 |
17 | GeneralJavaScript
18 |
19 |
20 | HTML
21 |
22 |
23 | JavaScript
24 |
25 |
26 | TypeScript
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Kushagra Agrawal
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/dist/components/DatePicker.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | display: flex;
3 | width: 100%;
4 | background: inherit;
5 | }
6 |
7 | .buttonWrapper {
8 | display: flex;
9 | align-items: flex-end;
10 | background: inherit;
11 | }
12 |
13 | .button {
14 | border: none;
15 | text-decoration: none;
16 | cursor: pointer;
17 | border-radius: 50%;
18 | width: 40px;
19 | height: 40px;
20 | color: white;
21 | font-size: 20px;
22 | font-weight: bold;
23 | flex-shrink: 0;
24 | display: flex;
25 | align-items: center;
26 | justify-content: center;
27 | padding: 0;
28 | margin-bottom: 13px;
29 | }
30 | .dateListScrollable {
31 | display: flex;
32 | overflow-x: scroll;
33 | scrollbar-width: none;
34 | margin: 2px 0 2px -40px;
35 | -webkit-overflow-scrolling: touch;
36 | }
37 |
38 | .dateListScrollable::-webkit-scrollbar {
39 | -webkit-appearance: none;
40 | display: none;
41 | }
42 |
43 | .monthContainer {
44 | display: flex;
45 | flex-direction: column;
46 | cursor: pointer;
47 | padding: 2px;
48 | margin: 2px;
49 | }
50 |
51 | .monthYearLabel {
52 | align-self: flex-start;
53 | z-index: 3;
54 | font-size: 15px;
55 | font-weight: bold;
56 | position: sticky;
57 | top: 10px;
58 | left: 0;
59 | width: max-content;
60 | margin: 0 10px;
61 | }
62 |
63 | .dateDayItem{
64 | display: flex;
65 | flex-direction: column;
66 | align-items: center;
67 | cursor: pointer;
68 | margin: 0 0 0 5px;
69 | width: 45px;
70 | height: 49px;
71 | flex-shrink: 0;
72 | }
73 |
74 | .daysContainer {
75 | display: flex;
76 | z-index: 1;
77 | margin-top: 10px;
78 | }
79 |
80 | .dayLabel {
81 | font-size: 12px;
82 | margin: 4px 0 0 0;
83 | }
84 |
85 | .dateLabel {
86 | font-size: 18px;
87 | }
--------------------------------------------------------------------------------
/src/components/DatePicker.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | display: flex;
3 | width: 100%;
4 | background: inherit;
5 | }
6 |
7 | .buttonWrapper {
8 | display: flex;
9 | align-items: flex-end;
10 | background: inherit;
11 | }
12 |
13 | .button {
14 | border: none;
15 | text-decoration: none;
16 | cursor: pointer;
17 | border-radius: 50%;
18 | width: 40px;
19 | height: 40px;
20 | color: white;
21 | font-size: 20px;
22 | font-weight: bold;
23 | flex-shrink: 0;
24 | display: flex;
25 | align-items: center;
26 | justify-content: center;
27 | padding: 0;
28 | margin-bottom: 13px;
29 | }
30 | .dateListScrollable {
31 | display: flex;
32 | overflow-x: scroll;
33 | scrollbar-width: none;
34 | margin: 2px 0 2px -40px;
35 | -webkit-overflow-scrolling: touch;
36 | }
37 |
38 | .dateListScrollable::-webkit-scrollbar {
39 | -webkit-appearance: none;
40 | display: none;
41 | }
42 |
43 | .monthContainer {
44 | display: flex;
45 | flex-direction: column;
46 | cursor: pointer;
47 | padding: 2px;
48 | margin: 2px;
49 | }
50 |
51 | .monthYearLabel {
52 | align-self: flex-start;
53 | z-index: 3;
54 | font-size: 15px;
55 | font-weight: bold;
56 | position: sticky;
57 | top: 10px;
58 | left: 0;
59 | width: max-content;
60 | margin: 0 10px;
61 | }
62 |
63 | .dateDayItem{
64 | display: flex;
65 | flex-direction: column;
66 | align-items: center;
67 | cursor: pointer;
68 | margin: 0 0 0 5px;
69 | width: 45px;
70 | height: 49px;
71 | flex-shrink: 0;
72 | }
73 |
74 | .daysContainer {
75 | display: flex;
76 | z-index: 1;
77 | margin-top: 10px;
78 | }
79 |
80 | .dayLabel {
81 | font-size: 12px;
82 | margin: 4px 0 0 0;
83 | }
84 |
85 | .dateLabel {
86 | font-size: 18px;
87 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## react-horizontal-datepicker
2 | #### V2 with new logic and completely removing dependency on react-waypoint as well as leaner code which now uses css-modules
3 |
4 | A simple and lightweight easily style-able Side scrolling datepicker, built with ❤️
5 |
6 | Bundle size of 469 Bytes Minified + Gzipped
7 |
8 | 
9 |
10 | ### Installation
11 |
12 | Run `yarn add react-horizontal-datepicker`
13 | or
14 | Run `npm i react-horizontal-datepicker`
15 |
16 | ### Usage
17 |
18 | Import:
19 |
20 | `import DatePicker from "react-horizontal-datepicker";`
21 |
22 | and simply use the component as:
23 |
24 | ```javascript
25 |
26 | ```
27 |
28 | example at the end
29 |
30 | #### Available Props are
31 |
32 | | Prop | Type | Default | Description |
33 | | ------------- |:-------:| :-------:| ----------- |
34 | | getSelectedDay | Function | | Function to get the selected Day |
35 | | endDate | Number| 90 | Number of days to render from current date |
36 | | selectDate | Date | | prop to send selected date manually or from another calendar component |
37 | | color | String | 'rgb(54, 105, 238)' | Set the primary color can be any color format in string |
38 | | labelFormat | String | 'MMMM yyyy' | Month label format - uses [date-fns format](https://date-fns.org/v1.30.1/docs/format) types |
39 |
40 | ### Example:
41 |
42 | https://codesandbox.io/s/vigilant-newton-gn0g7
43 |
44 | ```javascript
45 | function App() {
46 |
47 | const selectedDay = (val) =>{
48 | console.log(val)
49 | };
50 |
51 | return (
52 |
58 | );
59 | }
60 | ```
61 |
62 | ### Todo
63 | use react window for efficiency
64 |
65 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-horizontal-datepicker",
3 | "version": "2.0.3",
4 | "homepage": "https://github.com/kush-agra/react-horizontal-datepicker",
5 | "repository": {
6 | "type": "git",
7 | "url": "https://github.com/kush-agra/react-horizontal-datepicker.git"
8 | },
9 | "keywords": [
10 | "date-picker",
11 | "horizontal-calendar",
12 | "horizontal-datepicker",
13 | "swipeable",
14 | "side-scrolling",
15 | "calendar-strip",
16 | "web"
17 | ],
18 | "private": false,
19 | "main": "./dist/components/DatePicker.js",
20 | "license": "MIT",
21 | "author": "Kushagra Agrawal",
22 | "babel": {
23 | "presets": [
24 | "@babel/preset-react"
25 | ]
26 | },
27 | "dependencies": {
28 | "date-fns": "^2.14.0"
29 | },
30 | "peerDependencies": {
31 | "react": "^18.2.0",
32 | "react-dom": "^18.2.0",
33 | "react-scripts": "^5.0.1"
34 | },
35 | "scripts": {
36 | "publish:npm": "rm -rf dist && mkdir dist && mkdir dist/components && mkdir dist/global && babel src/components -d dist/components --copy-files && babel src/global -d dist/global --copy-files",
37 | "start": "react-scripts start",
38 | "build": "react-scripts build",
39 | "test": "react-scripts test",
40 | "eject": "react-scripts eject"
41 | },
42 | "eslintConfig": {
43 | "extends": "react-app"
44 | },
45 | "browserslist": {
46 | "production": [
47 | ">0.2%",
48 | "not dead",
49 | "not op_mini all"
50 | ],
51 | "development": [
52 | "last 1 chrome version",
53 | "last 1 firefox version",
54 | "last 1 safari version"
55 | ]
56 | },
57 | "devDependencies": {
58 | "@babel/cli": "^7.10.1",
59 | "@babel/preset-react": "^7.10.1",
60 | "react": "^18.2.0",
61 | "react-dom": "^18.2.0",
62 | "react-scripts": "^5.0.1"
63 | },
64 | "bit": {
65 | "env": {
66 | "compiler": "bit.envs/compilers/react@1.0.13"
67 | },
68 | "componentsDefaultDirectory": "components/{name}",
69 | "packageManager": "npm"
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/components/DatePicker.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable react-hooks/exhaustive-deps */
2 | import { addDays } from "date-fns";
3 | import React from "react";
4 | import hexToRgb from "../global/helpers/hexToRgb";
5 | import styles from "./DatePicker.module.css"
6 | import { DateView } from "./DateView";
7 | import { MonthView } from './MonthView';
8 |
9 | const DatePicker = (props) => {
10 | const next = (event) => {
11 | event.preventDefault();
12 | const e = document.getElementById('container');
13 | const width = e ? e.getBoundingClientRect().width : null;
14 | e.scrollLeft += width - 60;
15 | };
16 |
17 | const prev = (event) => {
18 | event.preventDefault();
19 | const e = document.getElementById('container');
20 | const width = e ? e.getBoundingClientRect().width : null;
21 | e.scrollLeft -= width - 60;
22 | };
23 |
24 | const primaryColor = props.color? (props.color.indexOf("rgb") > 0?props.color:hexToRgb(props.color)):'rgb(54, 105, 238)';
25 |
26 | const startDate = props.startDate || new Date();
27 | const lastDate = addDays(startDate, props.days || 90);
28 |
29 | let buttonzIndex = {zIndex: 2};
30 | let buttonStyle = {background: primaryColor};
31 | let Component = DateView;
32 | if(props.type === "month"){
33 | buttonzIndex = {zIndex: 5};
34 | Component = MonthView;
35 | buttonStyle = {background: primaryColor, marginBottom: "5px"};
36 | }
37 |
38 | return (
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | )
49 | }
50 |
51 | export { DatePicker }
--------------------------------------------------------------------------------
/dist/components/DatePicker.js:
--------------------------------------------------------------------------------
1 | function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
2 |
3 | /* eslint-disable react-hooks/exhaustive-deps */
4 | import { addDays } from "date-fns";
5 | import React from "react";
6 | import hexToRgb from "../global/helpers/hexToRgb";
7 | import styles from "./DatePicker.module.css";
8 | import { DateView } from "./DateView";
9 | import { MonthView } from './MonthView';
10 |
11 | const DatePicker = props => {
12 | const next = event => {
13 | event.preventDefault();
14 | const e = document.getElementById('container');
15 | const width = e ? e.getBoundingClientRect().width : null;
16 | e.scrollLeft += width - 60;
17 | };
18 |
19 | const prev = event => {
20 | event.preventDefault();
21 | const e = document.getElementById('container');
22 | const width = e ? e.getBoundingClientRect().width : null;
23 | e.scrollLeft -= width - 60;
24 | };
25 |
26 | const primaryColor = props.color ? props.color.indexOf("rgb") > 0 ? props.color : hexToRgb(props.color) : 'rgb(54, 105, 238)';
27 | const startDate = props.startDate || new Date();
28 | const lastDate = addDays(startDate, props.days || 90);
29 | let buttonzIndex = {
30 | zIndex: 2
31 | };
32 | let buttonStyle = {
33 | background: primaryColor
34 | };
35 | let Component = DateView;
36 |
37 | if (props.type === "month") {
38 | buttonzIndex = {
39 | zIndex: 5
40 | };
41 | Component = MonthView;
42 | buttonStyle = {
43 | background: primaryColor,
44 | marginBottom: "5px"
45 | };
46 | }
47 |
48 | return /*#__PURE__*/React.createElement("div", {
49 | className: styles.container
50 | }, /*#__PURE__*/React.createElement("div", {
51 | className: styles.buttonWrapper,
52 | style: buttonzIndex
53 | }, /*#__PURE__*/React.createElement("button", {
54 | className: styles.button,
55 | style: buttonStyle,
56 | onClick: prev
57 | }, "<")), /*#__PURE__*/React.createElement(Component, _extends({}, props, {
58 | primaryColor: primaryColor,
59 | startDate: startDate,
60 | lastDate: lastDate
61 | })), /*#__PURE__*/React.createElement("div", {
62 | className: styles.buttonWrapper,
63 | style: buttonzIndex
64 | }, /*#__PURE__*/React.createElement("button", {
65 | className: styles.button,
66 | style: buttonStyle,
67 | onClick: next
68 | }, ">")));
69 | };
70 |
71 | export { DatePicker };
--------------------------------------------------------------------------------
/dist/components/MonthView.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable react-hooks/exhaustive-deps */
2 | import React, { useEffect, useState } from "react";
3 | import styles from "./DatePicker.module.css";
4 | import { addMonths, differenceInMonths, format, isSameDay, startOfMonth } from "date-fns";
5 |
6 | const MonthView = ({
7 | startDate,
8 | lastDate,
9 | selectDate,
10 | getSelectedDay,
11 | primaryColor,
12 | labelFormat
13 | }) => {
14 | const [selectedDate, setSelectedDate] = useState(null);
15 | const rgb = primaryColor.replace(/[^\d,]/g, '').split(',');
16 | const brightness = Math.round((parseInt(rgb[0]) * 299 + parseInt(rgb[1]) * 587 + parseInt(rgb[2]) * 114) / 1000);
17 | const textColour = brightness > 125 ? 'black' : 'white';
18 | const selectedStyle = {
19 | borderRadius: "0.7rem",
20 | background: `${primaryColor}`,
21 | color: textColour
22 | };
23 |
24 | const getStyles = day => {
25 | return isSameDay(day, selectedDate) ? selectedStyle : null;
26 | };
27 |
28 | const getId = day => {
29 | return isSameDay(day, selectedDate) ? 'selected' : "";
30 | };
31 |
32 | const renderDays = () => {
33 | const months = [];
34 |
35 | for (let i = 0; i <= differenceInMonths(lastDate, startDate); i++) {
36 | const month = startOfMonth(addMonths(startDate, i));
37 | months.push( /*#__PURE__*/React.createElement("div", {
38 | id: `${getId(month)}`,
39 | className: styles.monthContainer,
40 | key: month,
41 | style: getStyles(month),
42 | onClick: () => onDateClick(month)
43 | }, /*#__PURE__*/React.createElement("span", {
44 | className: styles.monthYearLabel
45 | }, format(month, labelFormat || "MMMM yyyy"))));
46 | }
47 |
48 | return /*#__PURE__*/React.createElement("div", {
49 | id: "container",
50 | className: styles.dateListScrollable
51 | }, months);
52 | };
53 |
54 | const onDateClick = day => {
55 | setSelectedDate(day);
56 |
57 | if (getSelectedDay) {
58 | getSelectedDay(day);
59 | }
60 | };
61 |
62 | useEffect(() => {
63 | if (getSelectedDay) {
64 | if (selectDate) {
65 | getSelectedDay(selectDate);
66 | } else {
67 | getSelectedDay(startDate);
68 | }
69 | }
70 | }, []);
71 | useEffect(() => {
72 | if (selectDate) {
73 | if (!isSameDay(selectedDate, selectDate)) {
74 | setSelectedDate(selectDate);
75 | setTimeout(() => {
76 | let view = document.getElementById('selected');
77 |
78 | if (view) {
79 | view.scrollIntoView({
80 | behavior: "smooth",
81 | inline: "center",
82 | block: "nearest"
83 | });
84 | }
85 | }, 20);
86 | }
87 | }
88 | }, [selectDate]);
89 | return /*#__PURE__*/React.createElement(React.Fragment, null, renderDays());
90 | };
91 |
92 | export { MonthView };
--------------------------------------------------------------------------------
/src/components/MonthView.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable react-hooks/exhaustive-deps */
2 | import React, {useEffect, useState} from "react";
3 | import styles from "./DatePicker.module.css"
4 | import {
5 | addMonths,
6 | differenceInMonths,
7 | format,
8 | isSameDay,
9 | startOfMonth
10 | } from "date-fns";
11 |
12 |
13 | const MonthView = ({startDate, lastDate, selectDate, getSelectedDay, primaryColor, labelFormat}) => {
14 | const [selectedDate, setSelectedDate] = useState(null);
15 | const rgb = primaryColor.replace(/[^\d,]/g, '').split(',');
16 | const brightness = Math.round(((parseInt(rgb[0]) * 299) +
17 | (parseInt(rgb[1]) * 587) +
18 | (parseInt(rgb[2]) * 114)) / 1000);
19 | const textColour = (brightness > 125) ? 'black' : 'white';
20 |
21 | const selectedStyle = {borderRadius:"0.7rem",background:`${primaryColor}`, color: textColour};
22 |
23 | const getStyles = (day) => {
24 | return isSameDay(day, selectedDate)?selectedStyle:null;
25 | };
26 |
27 | const getId = (day) => {
28 | return isSameDay(day, selectedDate)?'selected':"";
29 | };
30 |
31 | const renderDays = () => {
32 |
33 | const months = [];
34 |
35 | for (let i = 0; i <= differenceInMonths(lastDate, startDate); i++) {
36 | const month = startOfMonth(addMonths(startDate, i));
37 | months.push(
38 | onDateClick(month)}
43 | >
44 |
45 | {format(month, labelFormat || "MMMM yyyy")}
46 |
47 |
48 | );
49 | }
50 |
51 | return {months}
;
52 | }
53 |
54 | const onDateClick = day => {
55 | setSelectedDate(day);
56 | if (getSelectedDay) {
57 | getSelectedDay(day);
58 | }
59 | };
60 |
61 | useEffect(() => {
62 | if (getSelectedDay) {
63 | if (selectDate) {
64 | getSelectedDay(selectDate);
65 | } else {
66 | getSelectedDay(startDate);
67 | }
68 | }
69 | }, []);
70 |
71 | useEffect(() => {
72 | if (selectDate) {
73 | if (!isSameDay(selectedDate, selectDate)) {
74 | setSelectedDate(selectDate);
75 | setTimeout(() => {
76 | let view = document.getElementById('selected');
77 | if (view) {
78 | view.scrollIntoView({behavior: "smooth", inline: "center", block: "nearest"});
79 | }
80 | }, 20);
81 | }
82 | }
83 | }, [selectDate]);
84 |
85 | return {renderDays()}
86 | }
87 |
88 |
89 |
90 |
91 | export { MonthView }
--------------------------------------------------------------------------------
/dist/components/DateView.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable react-hooks/exhaustive-deps */
2 | import React, { useEffect, useState } from "react";
3 | import styles from "./DatePicker.module.css";
4 | import { addDays, addMonths, differenceInMonths, format, isSameDay, lastDayOfMonth, startOfMonth } from "date-fns";
5 |
6 | const DateView = ({
7 | startDate,
8 | lastDate,
9 | selectDate,
10 | getSelectedDay,
11 | primaryColor,
12 | labelFormat
13 | }) => {
14 | const [selectedDate, setSelectedDate] = useState(null);
15 | const firstSection = {
16 | marginLeft: '40px'
17 | };
18 | const selectedStyle = {
19 | fontWeight: "bold",
20 | width: "45px",
21 | height: "45px",
22 | borderRadius: "50%",
23 | border: `2px solid ${primaryColor}`,
24 | color: primaryColor
25 | };
26 | const labelColor = {
27 | color: primaryColor
28 | };
29 |
30 | const getStyles = day => {
31 | return isSameDay(day, selectedDate) ? selectedStyle : null;
32 | };
33 |
34 | const getId = day => {
35 | return isSameDay(day, selectedDate) ? 'selected' : "";
36 | };
37 |
38 | const renderDays = () => {
39 | const dayFormat = "E";
40 | const dateFormat = "d";
41 | const months = [];
42 | let days = [];
43 |
44 | for (let i = 0; i <= differenceInMonths(lastDate, startDate); i++) {
45 | let start, end;
46 | const month = startOfMonth(addMonths(startDate, i));
47 | start = i === 0 ? Number(format(startDate, dateFormat)) - 1 : 0;
48 | end = i === differenceInMonths(lastDate, startDate) ? Number(format(lastDate, "d")) : Number(format(lastDayOfMonth(month), "d"));
49 |
50 | for (let j = start; j < end; j++) {
51 | let currentDay = addDays(month, j);
52 | days.push( /*#__PURE__*/React.createElement("div", {
53 | id: `${getId(currentDay)}`,
54 | className: styles.dateDayItem,
55 | style: getStyles(currentDay),
56 | key: currentDay,
57 | onClick: () => onDateClick(currentDay)
58 | }, /*#__PURE__*/React.createElement("div", {
59 | className: styles.dayLabel
60 | }, format(currentDay, dayFormat)), /*#__PURE__*/React.createElement("div", {
61 | className: styles.dateLabel
62 | }, format(currentDay, dateFormat))));
63 | }
64 |
65 | months.push( /*#__PURE__*/React.createElement("div", {
66 | className: styles.monthContainer,
67 | key: month
68 | }, /*#__PURE__*/React.createElement("span", {
69 | className: styles.monthYearLabel,
70 | style: labelColor
71 | }, format(month, labelFormat || "MMMM yyyy")), /*#__PURE__*/React.createElement("div", {
72 | className: styles.daysContainer,
73 | style: i === 0 ? firstSection : null
74 | }, days)));
75 | days = [];
76 | }
77 |
78 | return /*#__PURE__*/React.createElement("div", {
79 | id: "container",
80 | className: styles.dateListScrollable
81 | }, months);
82 | };
83 |
84 | const onDateClick = day => {
85 | setSelectedDate(day);
86 |
87 | if (getSelectedDay) {
88 | getSelectedDay(day);
89 | }
90 | };
91 |
92 | useEffect(() => {
93 | if (getSelectedDay) {
94 | if (selectDate) {
95 | getSelectedDay(selectDate);
96 | } else {
97 | getSelectedDay(startDate);
98 | }
99 | }
100 | }, []);
101 | useEffect(() => {
102 | if (selectDate) {
103 | if (!isSameDay(selectedDate, selectDate)) {
104 | setSelectedDate(selectDate);
105 | setTimeout(() => {
106 | let view = document.getElementById('selected');
107 |
108 | if (view) {
109 | view.scrollIntoView({
110 | behavior: "smooth",
111 | inline: "center",
112 | block: "nearest"
113 | });
114 | }
115 | }, 20);
116 | }
117 | }
118 | }, [selectDate]);
119 | return /*#__PURE__*/React.createElement(React.Fragment, null, renderDays());
120 | };
121 |
122 | export { DateView };
--------------------------------------------------------------------------------
/src/components/DateView.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable react-hooks/exhaustive-deps */
2 | import React, {useEffect, useState} from "react";
3 | import styles from "./DatePicker.module.css"
4 | import {
5 | addDays,
6 | addMonths,
7 | differenceInMonths,
8 | format,
9 | isSameDay,
10 | lastDayOfMonth,
11 | startOfMonth
12 | } from "date-fns";
13 |
14 |
15 | const DateView = ({startDate, lastDate, selectDate, getSelectedDay, primaryColor, labelFormat}) => {
16 | const [selectedDate, setSelectedDate] = useState(null);
17 | const firstSection = {marginLeft: '40px'};
18 | const selectedStyle = {fontWeight:"bold",width:"45px",height:"45px",borderRadius:"50%",border:`2px solid ${primaryColor}`,color:primaryColor};
19 | const labelColor = {color: primaryColor};
20 |
21 | const getStyles = (day) => {
22 | return isSameDay(day, selectedDate)?selectedStyle:null;
23 | };
24 |
25 | const getId = (day) => {
26 | return isSameDay(day, selectedDate)?'selected':"";
27 | };
28 |
29 | const renderDays = () => {
30 | const dayFormat = "E";
31 | const dateFormat = "d";
32 |
33 | const months = [];
34 | let days = [];
35 |
36 | for (let i = 0; i <= differenceInMonths(lastDate, startDate); i++) {
37 | let start, end;
38 | const month = startOfMonth(addMonths(startDate, i));
39 |
40 | start = i === 0 ? Number(format(startDate, dateFormat)) - 1 : 0;
41 | end = i === differenceInMonths(lastDate, startDate) ? Number(format(lastDate, "d")) : Number(format(lastDayOfMonth(month), "d"));
42 |
43 | for (let j = start; j < end; j++) {
44 | let currentDay = addDays(month, j);
45 |
46 | days.push(
47 | onDateClick(currentDay)}
52 | >
53 |
{format(currentDay, dayFormat)}
54 |
{format(currentDay, dateFormat)}
55 |
56 | );
57 | }
58 | months.push(
59 |
62 |
63 | {format(month, labelFormat || "MMMM yyyy")}
64 |
65 |
66 | {days}
67 |
68 |
69 | );
70 | days = [];
71 |
72 | }
73 |
74 | return {months}
;
75 | }
76 |
77 | const onDateClick = day => {
78 | setSelectedDate(day);
79 | if (getSelectedDay) {
80 | getSelectedDay(day);
81 | }
82 | };
83 |
84 | useEffect(() => {
85 | if (getSelectedDay) {
86 | if (selectDate) {
87 | getSelectedDay(selectDate);
88 | } else {
89 | getSelectedDay(startDate);
90 | }
91 | }
92 | }, []);
93 |
94 | useEffect(() => {
95 | if (selectDate) {
96 | if (!isSameDay(selectedDate, selectDate)) {
97 | setSelectedDate(selectDate);
98 | setTimeout(() => {
99 | let view = document.getElementById('selected');
100 | if (view) {
101 | view.scrollIntoView({behavior: "smooth", inline: "center", block: "nearest"});
102 | }
103 | }, 20);
104 | }
105 | }
106 | }, [selectDate]);
107 |
108 | return {renderDays()}
109 | }
110 |
111 |
112 |
113 |
114 | export { DateView }
--------------------------------------------------------------------------------