@acusti/date-picker 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,9 @@
1
+ # @acusti/date-picker
2
+
3
+ [![latest version](https://img.shields.io/npm/v/@acusti/css-value-input?style=for-the-badge)](https://www.npmjs.com/package/@acusti/css-value-input)
4
+ [![maintenance status](https://img.shields.io/npms-io/maintenance-score/@acusti/css-value-input?style=for-the-badge)](https://npms.io/search?q=%40acusti%2Fcss-value-input)
5
+ [![bundle size](https://img.shields.io/bundlephobia/minzip/@acusti/css-value-input?style=for-the-badge)](https://bundlephobia.com/package/@acusti/css-value-input)
6
+ [![downloads per month](https://img.shields.io/npm/dm/@acusti/css-value-input?style=for-the-badge)](https://www.npmjs.com/package/@acusti/css-value-input)
7
+
8
+ A group of React components and utils for rendering a date picker with
9
+ support for ranges via a two-up month calendar view.
@@ -0,0 +1,8 @@
1
+ import * as React from 'react';
2
+ export type Props = {
3
+ className?: string;
4
+ month: number;
5
+ onChange?: (event: React.SyntheticEvent<HTMLElement>) => void;
6
+ title?: string;
7
+ };
8
+ export default function MonthCalendar({ className, month, onChange, title }: Props): JSX.Element;
@@ -0,0 +1,57 @@
1
+ import { Style } from '@acusti/styling';
2
+ import clsx from 'clsx';
3
+ import * as React from 'react';
4
+ import { getMonthNameFromMonth, getYearFromMonth } from './utils.js';
5
+ import { ROOT_CLASS_NAME, STYLES } from './styles/month-calendar.js';
6
+ const { Fragment, useCallback } = React;
7
+ const DAYS = Array(7).fill(null);
8
+ export default function MonthCalendar({ className, month, onChange, title }) {
9
+ const year = getYearFromMonth(month);
10
+ title = title || `${getMonthNameFromMonth(month)} ${year}`;
11
+ const monthWithinYear = month % 12;
12
+ const firstDate = new Date(year, monthWithinYear, 1);
13
+ const nextMonth = month + 1;
14
+ const lastDate = new Date(getYearFromMonth(nextMonth), nextMonth % 12, 1);
15
+ lastDate.setDate(lastDate.getDate() - 1);
16
+ const totalDays = lastDate.getDate();
17
+ const firstDay = firstDate.getDay();
18
+ const spacesAfterLastDay = 7 - (lastDate.getDay() % 7); // prettier-ignore
19
+ const daySpaces = totalDays + firstDay + spacesAfterLastDay;
20
+ const handleClickDay = useCallback((event) => {
21
+ if (onChange)
22
+ onChange(event);
23
+ }, [onChange]);
24
+ return (React.createElement(Fragment, null,
25
+ React.createElement(Style, null, STYLES),
26
+ React.createElement("div", { className: clsx(ROOT_CLASS_NAME, className) },
27
+ React.createElement("div", { className: `${ROOT_CLASS_NAME}-month-item` },
28
+ React.createElement("div", { className: `${ROOT_CLASS_NAME}-month-title` },
29
+ React.createElement("h3", { className: `${ROOT_CLASS_NAME}-month-title-text` }, title)),
30
+ React.createElement("div", { className: `${ROOT_CLASS_NAME}-month-week` },
31
+ React.createElement("div", { className: "week-day-item" },
32
+ React.createElement("span", { className: "week-day-item-text" }, "Su")),
33
+ React.createElement("div", { className: "week-day-item" },
34
+ React.createElement("span", { className: "week-day-item-text" }, "Mo")),
35
+ React.createElement("div", { className: "week-day-item" },
36
+ React.createElement("span", { className: "week-day-item-text" }, "Tu")),
37
+ React.createElement("div", { className: "week-day-item" },
38
+ React.createElement("span", { className: "week-day-item-text" }, "We")),
39
+ React.createElement("div", { className: "week-day-item" },
40
+ React.createElement("span", { className: "week-day-item-text" }, "Th")),
41
+ React.createElement("div", { className: "week-day-item" },
42
+ React.createElement("span", { className: "week-day-item-text" }, "Fr")),
43
+ React.createElement("div", { className: "week-day-item" },
44
+ React.createElement("span", { className: "week-day-item-text" }, "Sa"))),
45
+ React.createElement("div", { className: `${ROOT_CLASS_NAME}-month-days` }, Array(Math.ceil(daySpaces / 7))
46
+ .fill(null)
47
+ .map((_, weekIndex) => (React.createElement("div", { className: `${ROOT_CLASS_NAME}-month-row`, key: `MonthRow-${weekIndex}` }, DAYS.map((_, dayIndex) => {
48
+ dayIndex += weekIndex * 7;
49
+ const dayNumber = (dayIndex - firstDay) + 1; // prettier-ignore
50
+ return (React.createElement("div", { className: `${ROOT_CLASS_NAME}-month-day-item`, key: `MonthDayItem-${dayNumber}`, onClick: handleClickDay },
51
+ React.createElement("span", { className: "month-day-item-text" }, dayNumber < 1 ||
52
+ dayNumber > totalDays
53
+ ? ''
54
+ : dayNumber)));
55
+ })))))))));
56
+ }
57
+ //# sourceMappingURL=MonthCalendar.js.map
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Flowtype definitions for MonthCalendar
3
+ * Generated by Flowgen from a Typescript Definition
4
+ * Flowgen v1.20.1
5
+ * @flow
6
+ */
7
+
8
+ import * as React from "react";
9
+ export type Props = {|
10
+ className?: string,
11
+ month: number,
12
+ onChange?: (event: SyntheticEvent<HTMLElement>) => void,
13
+ title?: string,
14
+ |};
15
+ declare export default function MonthCalendar(x: Props): React$Node;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MonthCalendar.js","sourceRoot":"","sources":["../src/MonthCalendar.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export { default as MonthCalendar } from './MonthCalendar.js';
2
+ export * from './utils.js';
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { default as MonthCalendar } from './MonthCalendar.js';
2
+ export * from './utils.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Flowtype definitions for index
3
+ * Generated by Flowgen from a Typescript Definition
4
+ * Flowgen v1.20.1
5
+ * @flow
6
+ */
7
+
8
+ declare export { default as MonthCalendar } from "./MonthCalendar.js";
9
+ declare export * from "./utils.js";
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAC9D,cAAc,YAAY,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const ROOT_CLASS_NAME = "uktmonthcalendar";
2
+ export declare const STYLES: string;
@@ -0,0 +1,152 @@
1
+ import { SYSTEM_UI_FONT } from '@acusti/styling';
2
+ export const ROOT_CLASS_NAME = 'uktmonthcalendar';
3
+ export const STYLES = `
4
+ .${ROOT_CLASS_NAME} {
5
+ display: flex;
6
+ flex: 1 1 auto;
7
+ justify-content: space-between;
8
+ font-family: ${SYSTEM_UI_FONT};
9
+ }
10
+
11
+ .${ROOT_CLASS_NAME}-month-item {
12
+ display: flex;
13
+ flex-direction: column;
14
+ flex: 1 1 auto;
15
+ box-sizing: border-box;
16
+ max-width: 325px;
17
+ }
18
+
19
+ .${ROOT_CLASS_NAME}-month-title {
20
+ display: flex;
21
+ align-items: center;
22
+ justify-content: center;
23
+ flex: 0 0 auto;
24
+ box-sizing: border-box;
25
+ padding-bottom: 25px;
26
+ }
27
+
28
+ h3.${ROOT_CLASS_NAME}-month-title-text {
29
+ font-size: 18px;
30
+ line-height: 23px;
31
+ font-weight: 600;
32
+ color: #000;
33
+ margin: 0px;
34
+ text-align: center;
35
+ }
36
+
37
+ .${ROOT_CLASS_NAME}-month-week {
38
+ flex: 0 0 auto;
39
+ display: grid;
40
+ grid-column-gap: 0px;
41
+ grid-template-columns: repeat(auto-fit, minmax(46px, 1fr));
42
+ grid-auto-flow: dense;
43
+ box-sizing: border-box;
44
+ padding-bottom: 12px;
45
+ }
46
+
47
+ .${ROOT_CLASS_NAME}-month-week .week-day-item {
48
+ flex: 1 1 auto;
49
+ display: flex;
50
+ justify-content: center;
51
+ align-items: center;
52
+ }
53
+
54
+ .${ROOT_CLASS_NAME}-month-week span.week-day-item-text {
55
+ text-align: center;
56
+ font-size: 13px;
57
+ line-height: 21px;
58
+ margin: 0px;
59
+ color: #9a9a9a;
60
+ }
61
+
62
+ .${ROOT_CLASS_NAME}-month-days {
63
+ flex: 1 1 auto;
64
+ display: flex;
65
+ flex-direction: column;
66
+ }
67
+
68
+ .${ROOT_CLASS_NAME}-month-row {
69
+ flex: 1 1 auto;
70
+ display: grid;
71
+ grid-column-gap: 0px;
72
+ grid-template-columns: repeat(auto-fit, minmax(46px, 1fr));
73
+ grid-auto-flow: dense;
74
+ margin-bottom: 1px;
75
+ }
76
+
77
+ .${ROOT_CLASS_NAME}-month-day-item {
78
+ display: flex;
79
+ justify-content: center;
80
+ align-items: center;
81
+ position: relative;
82
+ height: 46px;
83
+ width: 46px;
84
+ cursor: pointer;
85
+ }
86
+
87
+ .${ROOT_CLASS_NAME}-month-day-item.selected {
88
+ background-color: #f8f8f8;
89
+ }
90
+
91
+ .${ROOT_CLASS_NAME}-month-day-item.start-date {
92
+ background-color: #f8f8f8;
93
+ border-top-left-radius: 50%;
94
+ border-bottom-left-radius: 50%;
95
+ }
96
+
97
+ .${ROOT_CLASS_NAME}-month-day-item.start-date:after {
98
+ background-color: #000;
99
+ opacity: 1;
100
+ visibility: visible;
101
+ }
102
+ .${ROOT_CLASS_NAME}-month-day-item.start-date span.month-day-item-text {
103
+ color: #fff;
104
+ }
105
+
106
+ .${ROOT_CLASS_NAME}-month-day-item.end-date {
107
+ background-color: #f8f8f8;
108
+ border-top-right-radius: 50%;
109
+ border-bottom-right-radius: 50%;
110
+ }
111
+
112
+ .${ROOT_CLASS_NAME}-month-day-item.end-date:after {
113
+ background-color: #000;
114
+ opacity: 1;
115
+ visibility: visible;
116
+ }
117
+ .${ROOT_CLASS_NAME}-month-day-item.end-date span.month-day-item-text {
118
+ color: #fff;
119
+ }
120
+
121
+ .${ROOT_CLASS_NAME}-month-day-item:hover:after {
122
+ opacity: 1;
123
+ visibility: visible;
124
+ }
125
+
126
+ .${ROOT_CLASS_NAME}-month-day-item:after {
127
+ content: "";
128
+ position: absolute;
129
+ left: 50%;
130
+ top: 50%;
131
+ transform: translate(-50%, -50%);
132
+ pointer-events: none;
133
+ border-radius: 50%;
134
+ border: 1px solid #000;
135
+ width: 43px;
136
+ height: 43px;
137
+ transition: opacity 0.25s ease-in-out;
138
+ opacity: 0;
139
+ visibility: hidden;
140
+ }
141
+
142
+ .${ROOT_CLASS_NAME}-month-day-item span.month-day-item-text {
143
+ text-align: center;
144
+ font-size: 13px;
145
+ line-height: 21px;
146
+ margin: 0px;
147
+ color: #000;
148
+ position: relative;
149
+ z-index: 1;
150
+ }
151
+ `;
152
+ //# sourceMappingURL=month-calendar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"month-calendar.js","sourceRoot":"","sources":["../../src/styles/month-calendar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD,MAAM,CAAC,MAAM,eAAe,GAAG,kBAAkB,CAAC;AAElD,MAAM,CAAC,MAAM,MAAM,GAAG;GACnB,eAAe;;;;mBAIC,cAAc;;;GAG9B,eAAe;;;;;;;;GAQf,eAAe;;;;;;;;;KASb,eAAe;;;;;;;;;GASjB,eAAe;;;;;;;;;;GAUf,eAAe;;;;;;;GAOf,eAAe;;;;;;;;GAQf,eAAe;;;;;;GAMf,eAAe;;;;;;;;;GASf,eAAe;;;;;;;;;;GAUf,eAAe;;;;GAIf,eAAe;;;;;;GAMf,eAAe;;;;;GAKf,eAAe;;;;GAIf,eAAe;;;;;;GAMf,eAAe;;;;;GAKf,eAAe;;;;GAIf,eAAe;;;;;GAKf,eAAe;;;;;;;;;;;;;;;;GAgBf,eAAe;;;;;;;;;CASjB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare const getMonthFromDate: (date: Date) => number;
2
+ export declare const getYearFromMonth: (month: number) => number;
3
+ export declare const getMonthNameFromMonth: (month: number) => string;
4
+ export declare const getMonthAbbreviationFromMonth: (month: number) => string;
package/dist/utils.js ADDED
@@ -0,0 +1,28 @@
1
+ // The following utils work on a “month” as a unique numerical value
2
+ // representing the number of months since the unix epoch (jan 1970)
3
+ const START_YEAR = 1970;
4
+ const MONTH_NAMES = [
5
+ 'January',
6
+ 'February',
7
+ 'March',
8
+ 'April',
9
+ 'May',
10
+ 'June',
11
+ 'July',
12
+ 'August',
13
+ 'September',
14
+ 'October',
15
+ 'November',
16
+ 'December',
17
+ ];
18
+ const getYearFromDate = (date) => date.getFullYear() - START_YEAR;
19
+ export const getMonthFromDate = (date) => date.getMonth() + (getYearFromDate(date) * 12); // prettier-ignore
20
+ export const getYearFromMonth = (month) => Math.floor(month / 12) + START_YEAR;
21
+ export const getMonthNameFromMonth = (month) => MONTH_NAMES[month % 12];
22
+ export const getMonthAbbreviationFromMonth = (month) => {
23
+ const monthName = getMonthNameFromMonth(month);
24
+ if (monthName === 'September')
25
+ return 'Sept';
26
+ return monthName.substring(0, 3);
27
+ };
28
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Flowtype definitions for utils
3
+ * Generated by Flowgen from a Typescript Definition
4
+ * Flowgen v1.20.1
5
+ * @flow
6
+ */
7
+
8
+ declare export var getMonthFromDate: (date: Date) => number;
9
+ declare export var getYearFromMonth: (month: number) => number;
10
+ declare export var getMonthNameFromMonth: (month: number) => string;
11
+ declare export var getMonthAbbreviationFromMonth: (month: number) => string;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,oEAAoE;AACpE,MAAM,UAAU,GAAG,IAAI,CAAC;AACxB,MAAM,WAAW,GAAG;IAChB,SAAS;IACT,UAAU;IACV,OAAO;IACP,OAAO;IACP,KAAK;IACL,MAAM;IACN,MAAM;IACN,QAAQ;IACR,WAAW;IACX,SAAS;IACT,UAAU;IACV,UAAU;CACb,CAAC;AAEF,MAAM,eAAe,GAAG,CAAC,IAAU,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,UAAU,CAAC;AAExE,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,IAAU,EAAE,EAAE,CAC3C,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,kBAAkB;AAEtE,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC,GAAG,UAAU,CAAC;AAEvF,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,WAAW,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC;AAEhF,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,KAAa,EAAE,EAAE;IAC3D,MAAM,SAAS,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;IAC/C,IAAI,SAAS,KAAK,WAAW;QAAE,OAAO,MAAM,CAAC;IAC7C,OAAO,SAAS,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACrC,CAAC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@acusti/date-picker",
3
+ "version": "0.0.1",
4
+ "description": "React component that renders a date picker with the option to choose a range",
5
+ "keywords": [
6
+ "react",
7
+ "react-component",
8
+ "datepicker",
9
+ "date-picker",
10
+ "daterangepicker",
11
+ "date-range-picker",
12
+ "date",
13
+ "picker",
14
+ "form",
15
+ "input",
16
+ "ssr",
17
+ "typescript",
18
+ "ts",
19
+ "flow"
20
+ ],
21
+ "type": "module",
22
+ "sideEffects": false,
23
+ "exports": "./dist/index.js",
24
+ "main": "./dist/index.js",
25
+ "types": "./dist/index.d.ts",
26
+ "files": [
27
+ "dist",
28
+ "src"
29
+ ],
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "https://github.com/acusti/uikit.git",
33
+ "directory": "packages/date-picker"
34
+ },
35
+ "author": "andrew patton <andrew@acusti.ca> (https://www.acusti.ca)",
36
+ "license": "Unlicense",
37
+ "bugs": {
38
+ "url": "https://github.com/acusti/uikit/issues"
39
+ },
40
+ "homepage": "https://github.com/acusti/uikit/tree/main/packages/date-picker#readme",
41
+ "devDependencies": {
42
+ "@testing-library/dom": "^9.3.1",
43
+ "@testing-library/react": "^14.0.0",
44
+ "@testing-library/user-event": "^14.4.3",
45
+ "@types/react": "^18.0.25",
46
+ "jsdom": "^22.1.0",
47
+ "react": "^18",
48
+ "react-dom": "^18",
49
+ "typescript": "^5.1.6"
50
+ },
51
+ "dependencies": {
52
+ "@acusti/styling": "^0.6.0",
53
+ "clsx": "^2"
54
+ },
55
+ "peerDependencies": {
56
+ "react": "^16.8 || ^17 || ^18",
57
+ "react-dom": "^16.8 || ^17 || ^18"
58
+ }
59
+ }
@@ -0,0 +1,103 @@
1
+ import { Style } from '@acusti/styling';
2
+ import clsx from 'clsx';
3
+ import * as React from 'react';
4
+
5
+ import { getMonthNameFromMonth, getYearFromMonth } from './utils.js';
6
+ import { ROOT_CLASS_NAME, STYLES } from './styles/month-calendar.js';
7
+
8
+ export type Props = {
9
+ className?: string;
10
+ month: number; // a unique numerical value representing the number of months since jan 1970
11
+ onChange?: (event: React.SyntheticEvent<HTMLElement>) => void;
12
+ title?: string;
13
+ };
14
+
15
+ const { Fragment, useCallback } = React;
16
+
17
+ const DAYS = Array(7).fill(null);
18
+
19
+ export default function MonthCalendar({ className, month, onChange, title }: Props) {
20
+ const year = getYearFromMonth(month);
21
+ title = title || `${getMonthNameFromMonth(month)} ${year}`;
22
+ const monthWithinYear = month % 12;
23
+ const firstDate = new Date(year, monthWithinYear, 1);
24
+ const nextMonth = month + 1;
25
+ const lastDate = new Date(getYearFromMonth(nextMonth), nextMonth % 12, 1);
26
+ lastDate.setDate(lastDate.getDate() - 1);
27
+ const totalDays = lastDate.getDate();
28
+ const firstDay = firstDate.getDay();
29
+ const spacesAfterLastDay = 7 - (lastDate.getDay() % 7); // prettier-ignore
30
+ const daySpaces = totalDays + firstDay + spacesAfterLastDay;
31
+
32
+ const handleClickDay = useCallback(
33
+ (event: React.SyntheticEvent<HTMLElement>) => {
34
+ if (onChange) onChange(event);
35
+ },
36
+ [onChange],
37
+ );
38
+
39
+ return (
40
+ <Fragment>
41
+ <Style>{STYLES}</Style>
42
+ <div className={clsx(ROOT_CLASS_NAME, className)}>
43
+ <div className={`${ROOT_CLASS_NAME}-month-item`}>
44
+ <div className={`${ROOT_CLASS_NAME}-month-title`}>
45
+ <h3 className={`${ROOT_CLASS_NAME}-month-title-text`}>{title}</h3>
46
+ </div>
47
+ <div className={`${ROOT_CLASS_NAME}-month-week`}>
48
+ <div className="week-day-item">
49
+ <span className="week-day-item-text">Su</span>
50
+ </div>
51
+ <div className="week-day-item">
52
+ <span className="week-day-item-text">Mo</span>
53
+ </div>
54
+ <div className="week-day-item">
55
+ <span className="week-day-item-text">Tu</span>
56
+ </div>
57
+ <div className="week-day-item">
58
+ <span className="week-day-item-text">We</span>
59
+ </div>
60
+ <div className="week-day-item">
61
+ <span className="week-day-item-text">Th</span>
62
+ </div>
63
+ <div className="week-day-item">
64
+ <span className="week-day-item-text">Fr</span>
65
+ </div>
66
+ <div className="week-day-item">
67
+ <span className="week-day-item-text">Sa</span>
68
+ </div>
69
+ </div>
70
+ <div className={`${ROOT_CLASS_NAME}-month-days`}>
71
+ {Array(Math.ceil(daySpaces / 7))
72
+ .fill(null)
73
+ .map((_, weekIndex) => (
74
+ <div
75
+ className={`${ROOT_CLASS_NAME}-month-row`}
76
+ key={`MonthRow-${weekIndex}`}
77
+ >
78
+ {DAYS.map((_, dayIndex) => {
79
+ dayIndex += weekIndex * 7;
80
+ const dayNumber = (dayIndex - firstDay) + 1; // prettier-ignore
81
+ return (
82
+ <div
83
+ className={`${ROOT_CLASS_NAME}-month-day-item`}
84
+ key={`MonthDayItem-${dayNumber}`}
85
+ onClick={handleClickDay}
86
+ >
87
+ <span className="month-day-item-text">
88
+ {dayNumber < 1 ||
89
+ dayNumber > totalDays
90
+ ? ''
91
+ : dayNumber}
92
+ </span>
93
+ </div>
94
+ );
95
+ })}
96
+ </div>
97
+ ))}
98
+ </div>
99
+ </div>
100
+ </div>
101
+ </Fragment>
102
+ );
103
+ }
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { default as MonthCalendar } from './MonthCalendar.js';
2
+ export * from './utils.js';
@@ -0,0 +1,153 @@
1
+ import { SYSTEM_UI_FONT } from '@acusti/styling';
2
+
3
+ export const ROOT_CLASS_NAME = 'uktmonthcalendar';
4
+
5
+ export const STYLES = `
6
+ .${ROOT_CLASS_NAME} {
7
+ display: flex;
8
+ flex: 1 1 auto;
9
+ justify-content: space-between;
10
+ font-family: ${SYSTEM_UI_FONT};
11
+ }
12
+
13
+ .${ROOT_CLASS_NAME}-month-item {
14
+ display: flex;
15
+ flex-direction: column;
16
+ flex: 1 1 auto;
17
+ box-sizing: border-box;
18
+ max-width: 325px;
19
+ }
20
+
21
+ .${ROOT_CLASS_NAME}-month-title {
22
+ display: flex;
23
+ align-items: center;
24
+ justify-content: center;
25
+ flex: 0 0 auto;
26
+ box-sizing: border-box;
27
+ padding-bottom: 25px;
28
+ }
29
+
30
+ h3.${ROOT_CLASS_NAME}-month-title-text {
31
+ font-size: 18px;
32
+ line-height: 23px;
33
+ font-weight: 600;
34
+ color: #000;
35
+ margin: 0px;
36
+ text-align: center;
37
+ }
38
+
39
+ .${ROOT_CLASS_NAME}-month-week {
40
+ flex: 0 0 auto;
41
+ display: grid;
42
+ grid-column-gap: 0px;
43
+ grid-template-columns: repeat(auto-fit, minmax(46px, 1fr));
44
+ grid-auto-flow: dense;
45
+ box-sizing: border-box;
46
+ padding-bottom: 12px;
47
+ }
48
+
49
+ .${ROOT_CLASS_NAME}-month-week .week-day-item {
50
+ flex: 1 1 auto;
51
+ display: flex;
52
+ justify-content: center;
53
+ align-items: center;
54
+ }
55
+
56
+ .${ROOT_CLASS_NAME}-month-week span.week-day-item-text {
57
+ text-align: center;
58
+ font-size: 13px;
59
+ line-height: 21px;
60
+ margin: 0px;
61
+ color: #9a9a9a;
62
+ }
63
+
64
+ .${ROOT_CLASS_NAME}-month-days {
65
+ flex: 1 1 auto;
66
+ display: flex;
67
+ flex-direction: column;
68
+ }
69
+
70
+ .${ROOT_CLASS_NAME}-month-row {
71
+ flex: 1 1 auto;
72
+ display: grid;
73
+ grid-column-gap: 0px;
74
+ grid-template-columns: repeat(auto-fit, minmax(46px, 1fr));
75
+ grid-auto-flow: dense;
76
+ margin-bottom: 1px;
77
+ }
78
+
79
+ .${ROOT_CLASS_NAME}-month-day-item {
80
+ display: flex;
81
+ justify-content: center;
82
+ align-items: center;
83
+ position: relative;
84
+ height: 46px;
85
+ width: 46px;
86
+ cursor: pointer;
87
+ }
88
+
89
+ .${ROOT_CLASS_NAME}-month-day-item.selected {
90
+ background-color: #f8f8f8;
91
+ }
92
+
93
+ .${ROOT_CLASS_NAME}-month-day-item.start-date {
94
+ background-color: #f8f8f8;
95
+ border-top-left-radius: 50%;
96
+ border-bottom-left-radius: 50%;
97
+ }
98
+
99
+ .${ROOT_CLASS_NAME}-month-day-item.start-date:after {
100
+ background-color: #000;
101
+ opacity: 1;
102
+ visibility: visible;
103
+ }
104
+ .${ROOT_CLASS_NAME}-month-day-item.start-date span.month-day-item-text {
105
+ color: #fff;
106
+ }
107
+
108
+ .${ROOT_CLASS_NAME}-month-day-item.end-date {
109
+ background-color: #f8f8f8;
110
+ border-top-right-radius: 50%;
111
+ border-bottom-right-radius: 50%;
112
+ }
113
+
114
+ .${ROOT_CLASS_NAME}-month-day-item.end-date:after {
115
+ background-color: #000;
116
+ opacity: 1;
117
+ visibility: visible;
118
+ }
119
+ .${ROOT_CLASS_NAME}-month-day-item.end-date span.month-day-item-text {
120
+ color: #fff;
121
+ }
122
+
123
+ .${ROOT_CLASS_NAME}-month-day-item:hover:after {
124
+ opacity: 1;
125
+ visibility: visible;
126
+ }
127
+
128
+ .${ROOT_CLASS_NAME}-month-day-item:after {
129
+ content: "";
130
+ position: absolute;
131
+ left: 50%;
132
+ top: 50%;
133
+ transform: translate(-50%, -50%);
134
+ pointer-events: none;
135
+ border-radius: 50%;
136
+ border: 1px solid #000;
137
+ width: 43px;
138
+ height: 43px;
139
+ transition: opacity 0.25s ease-in-out;
140
+ opacity: 0;
141
+ visibility: hidden;
142
+ }
143
+
144
+ .${ROOT_CLASS_NAME}-month-day-item span.month-day-item-text {
145
+ text-align: center;
146
+ font-size: 13px;
147
+ line-height: 21px;
148
+ margin: 0px;
149
+ color: #000;
150
+ position: relative;
151
+ z-index: 1;
152
+ }
153
+ `;
package/src/utils.ts ADDED
@@ -0,0 +1,32 @@
1
+ // The following utils work on a “month” as a unique numerical value
2
+ // representing the number of months since the unix epoch (jan 1970)
3
+ const START_YEAR = 1970;
4
+ const MONTH_NAMES = [
5
+ 'January',
6
+ 'February',
7
+ 'March',
8
+ 'April',
9
+ 'May',
10
+ 'June',
11
+ 'July',
12
+ 'August',
13
+ 'September',
14
+ 'October',
15
+ 'November',
16
+ 'December',
17
+ ];
18
+
19
+ const getYearFromDate = (date: Date) => date.getFullYear() - START_YEAR;
20
+
21
+ export const getMonthFromDate = (date: Date) =>
22
+ date.getMonth() + (getYearFromDate(date) * 12); // prettier-ignore
23
+
24
+ export const getYearFromMonth = (month: number) => Math.floor(month / 12) + START_YEAR;
25
+
26
+ export const getMonthNameFromMonth = (month: number) => MONTH_NAMES[month % 12];
27
+
28
+ export const getMonthAbbreviationFromMonth = (month: number) => {
29
+ const monthName = getMonthNameFromMonth(month);
30
+ if (monthName === 'September') return 'Sept';
31
+ return monthName.substring(0, 3);
32
+ };