@instructure/ui-calendar 8.51.0 → 8.51.1-snapshot-5

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.
@@ -14,13 +14,20 @@ var _omitProps = require("@instructure/ui-react-utils/lib/omitProps.js");
14
14
  var _createChainedFunction = require("@instructure/ui-utils/lib/createChainedFunction.js");
15
15
  var _console = require("@instructure/console");
16
16
  var _uid = require("@instructure/uid");
17
+ var _AccessibleContent = require("@instructure/ui-a11y-content/lib/AccessibleContent");
17
18
  var _testable = require("@instructure/ui-testable/lib/testable.js");
18
19
  var _emotion = require("@instructure/emotion");
20
+ var _Locale = require("@instructure/ui-i18n/lib/Locale.js");
21
+ var _DateTime = require("@instructure/ui-i18n/lib/DateTime.js");
22
+ var _ApplyLocaleContext = require("@instructure/ui-i18n/lib/ApplyLocale/ApplyLocaleContext.js");
19
23
  var _styles = _interopRequireDefault(require("./styles"));
20
24
  var _theme = _interopRequireDefault(require("./theme"));
21
25
  var _Day = require("./Day");
22
26
  var _props = require("./props");
23
- var _dec, _dec2, _class, _class2;
27
+ var _IconButton3 = require("@instructure/ui-buttons/lib/IconButton");
28
+ var _IconArrowOpenStartSolid = require("@instructure/ui-icons/lib/IconArrowOpenStartSolid.js");
29
+ var _IconArrowOpenEndSolid = require("@instructure/ui-icons/lib/IconArrowOpenEndSolid.js");
30
+ var _dec, _dec2, _class, _class2, _IconButton, _IconButton2;
24
31
  /*
25
32
  * The MIT License (MIT)
26
33
  *
@@ -51,10 +58,10 @@ category: components
51
58
  ---
52
59
  **/
53
60
  let Calendar = exports.Calendar = (_dec = (0, _emotion.withStyle)(_styles.default, _theme.default), _dec2 = (0, _testable.testable)(), _dec(_class = _dec2(_class = (_class2 = class Calendar extends _react.Component {
54
- constructor(...args) {
55
- super(...args);
61
+ constructor(props) {
62
+ super(props);
56
63
  this.ref = null;
57
- this._weekdayHeaderIds = this.props.renderWeekdayLabels.reduce((ids, _label, i) => {
64
+ this._weekdayHeaderIds = (this.props.renderWeekdayLabels || this.defaultWeekdays).reduce((ids, _label, i) => {
58
65
  return {
59
66
  ...ids,
60
67
  [i]: (0, _uid.uid)(`weekday-header-${i}`)
@@ -63,35 +70,107 @@ let Calendar = exports.Calendar = (_dec = (0, _emotion.withStyle)(_styles.defaul
63
70
  this.handleRef = el => {
64
71
  this.ref = el;
65
72
  };
73
+ this.calculateState = (locale, timezone, currentDate) => ({
74
+ renderedDate: currentDate ? _DateTime.DateTime.parse(currentDate, locale, timezone) : _DateTime.DateTime.now(locale, timezone),
75
+ today: currentDate ? _DateTime.DateTime.parse(currentDate, locale, timezone) : _DateTime.DateTime.now(locale, timezone)
76
+ });
77
+ this.renderMonthNavigationButtons = () => {
78
+ const _this$props = this.props,
79
+ renderNextMonthButton = _this$props.renderNextMonthButton,
80
+ renderPrevMonthButton = _this$props.renderPrevMonthButton;
81
+ return {
82
+ prevButton: renderPrevMonthButton ? (0, _callRenderProp.callRenderProp)(renderPrevMonthButton) : _IconButton || (_IconButton = (0, _emotion.jsx)(_IconButton3.IconButton, {
83
+ size: "small",
84
+ withBackground: false,
85
+ withBorder: false,
86
+ renderIcon: (0, _emotion.jsx)(_IconArrowOpenStartSolid.IconArrowOpenStartSolid, {
87
+ color: "primary"
88
+ }),
89
+ screenReaderLabel: "Previous month"
90
+ })),
91
+ nextButton: renderNextMonthButton ? (0, _callRenderProp.callRenderProp)(renderNextMonthButton) : _IconButton2 || (_IconButton2 = (0, _emotion.jsx)(_IconButton3.IconButton, {
92
+ size: "small",
93
+ withBackground: false,
94
+ withBorder: false,
95
+ renderIcon: (0, _emotion.jsx)(_IconArrowOpenEndSolid.IconArrowOpenEndSolid, {
96
+ color: "primary"
97
+ }),
98
+ screenReaderLabel: "Next month"
99
+ }))
100
+ };
101
+ };
102
+ this.handleMonthChange = direction => e => {
103
+ const _this$props2 = this.props,
104
+ onRequestRenderNextMonth = _this$props2.onRequestRenderNextMonth,
105
+ onRequestRenderPrevMonth = _this$props2.onRequestRenderPrevMonth;
106
+ const renderedDate = this.state.renderedDate;
107
+ const newDate = renderedDate.clone();
108
+ if (direction === 'prev') {
109
+ if (onRequestRenderPrevMonth) {
110
+ onRequestRenderPrevMonth(e);
111
+ return;
112
+ }
113
+ newDate.subtract({
114
+ months: 1
115
+ });
116
+ } else {
117
+ if (onRequestRenderNextMonth) {
118
+ onRequestRenderNextMonth(e);
119
+ return;
120
+ }
121
+ newDate.add({
122
+ months: 1
123
+ });
124
+ }
125
+ this.setState({
126
+ renderedDate: newDate
127
+ });
128
+ };
129
+ // date is returned es a ISO string, like 2021-09-14T22:00:00.000Z
130
+ this.handleDayClick = (event, {
131
+ date
132
+ }) => {
133
+ if (this.props.onDateSelected) {
134
+ const parsedDate = _DateTime.DateTime.parse(date, this.locale(), this.timezone());
135
+ this.props.onDateSelected(parsedDate.toISOString(), parsedDate, event);
136
+ }
137
+ };
138
+ this.state = this.calculateState(this.locale(), this.timezone(), props.currentDate);
66
139
  }
67
140
  componentDidMount() {
68
- var _this$props$makeStyle, _this$props;
69
- (_this$props$makeStyle = (_this$props = this.props).makeStyles) === null || _this$props$makeStyle === void 0 ? void 0 : _this$props$makeStyle.call(_this$props);
141
+ var _this$props$makeStyle, _this$props3;
142
+ (_this$props$makeStyle = (_this$props3 = this.props).makeStyles) === null || _this$props$makeStyle === void 0 ? void 0 : _this$props$makeStyle.call(_this$props3);
70
143
  }
71
- componentDidUpdate() {
72
- var _this$props$makeStyle2, _this$props2;
73
- (_this$props$makeStyle2 = (_this$props2 = this.props).makeStyles) === null || _this$props$makeStyle2 === void 0 ? void 0 : _this$props$makeStyle2.call(_this$props2);
144
+ componentDidUpdate(prevProps) {
145
+ var _this$props$makeStyle2, _this$props4;
146
+ (_this$props$makeStyle2 = (_this$props4 = this.props).makeStyles) === null || _this$props$makeStyle2 === void 0 ? void 0 : _this$props$makeStyle2.call(_this$props4);
147
+ const isUpdated = prevProps.locale !== this.props.locale || prevProps.timezone !== this.props.timezone;
148
+ if (isUpdated) {
149
+ this.setState(() => {
150
+ return {
151
+ ...this.calculateState(this.locale(), this.timezone(), this.props.currentDate)
152
+ };
153
+ });
154
+ }
74
155
  }
75
156
  get role() {
76
157
  return this.props.role === 'listbox' ? this.props.role : void 0;
77
158
  }
78
159
  renderHeader() {
79
- const _this$props3 = this.props,
80
- renderNextMonthButton = _this$props3.renderNextMonthButton,
81
- renderPrevMonthButton = _this$props3.renderPrevMonthButton,
82
- renderNavigationLabel = _this$props3.renderNavigationLabel,
83
- onRequestRenderNextMonth = _this$props3.onRequestRenderNextMonth,
84
- onRequestRenderPrevMonth = _this$props3.onRequestRenderPrevMonth,
85
- styles = _this$props3.styles;
86
- const nextButton = (0, _callRenderProp.callRenderProp)(renderNextMonthButton);
87
- const prevButton = (0, _callRenderProp.callRenderProp)(renderPrevMonthButton);
160
+ const _this$props5 = this.props,
161
+ renderNavigationLabel = _this$props5.renderNavigationLabel,
162
+ styles = _this$props5.styles;
163
+ const renderedDate = this.state.renderedDate;
164
+ const _this$renderMonthNavi = this.renderMonthNavigationButtons(),
165
+ prevButton = _this$renderMonthNavi.prevButton,
166
+ nextButton = _this$renderMonthNavi.nextButton;
88
167
  const cloneButton = (button, onClick) => (0, _safeCloneElement.safeCloneElement)(button, {
89
168
  onClick: (0, _createChainedFunction.createChainedFunction)(button.props.onClick, onClick)
90
169
  });
91
170
  const style = [styles === null || styles === void 0 ? void 0 : styles.navigation, ...(prevButton || nextButton ? [styles === null || styles === void 0 ? void 0 : styles.navigationWithButtons] : [])];
92
171
  return (0, _emotion.jsx)("div", {
93
172
  css: style
94
- }, prevButton && cloneButton(prevButton, onRequestRenderPrevMonth), (0, _callRenderProp.callRenderProp)(renderNavigationLabel), nextButton && cloneButton(nextButton, onRequestRenderNextMonth));
173
+ }, prevButton && cloneButton(prevButton, this.handleMonthChange('prev')), renderNavigationLabel ? (0, _callRenderProp.callRenderProp)(renderNavigationLabel) : (0, _emotion.jsx)("span", null, (0, _emotion.jsx)("div", null, renderedDate.format('MMMM')), (0, _emotion.jsx)("div", null, renderedDate.format('YYYY'))), nextButton && cloneButton(nextButton, this.handleMonthChange('next')));
95
174
  }
96
175
  renderBody() {
97
176
  return (0, _emotion.jsx)("table", {
@@ -99,9 +178,8 @@ let Calendar = exports.Calendar = (_dec = (0, _emotion.withStyle)(_styles.defaul
99
178
  }, (0, _emotion.jsx)("thead", null, this.renderWeekdayHeaders()), (0, _emotion.jsx)("tbody", null, this.renderDays()));
100
179
  }
101
180
  renderWeekdayHeaders() {
102
- const _this$props4 = this.props,
103
- renderWeekdayLabels = _this$props4.renderWeekdayLabels,
104
- styles = _this$props4.styles;
181
+ const styles = this.props.styles;
182
+ const renderWeekdayLabels = this.props.renderWeekdayLabels || this.defaultWeekdays;
105
183
  const length = renderWeekdayLabels.length;
106
184
  (0, _console.logError)(length === 7, `[Calendar] \`renderWeekdayLabels\` should be an array with 7 labels (one for each weekday). ${length} provided.`);
107
185
  return (0, _emotion.jsx)("tr", null, renderWeekdayLabels.map((label, i) => {
@@ -113,12 +191,39 @@ let Calendar = exports.Calendar = (_dec = (0, _emotion.withStyle)(_styles.defaul
113
191
  }, (0, _callRenderProp.callRenderProp)(label));
114
192
  }));
115
193
  }
194
+ get defaultWeekdays() {
195
+ const shortDayNames = _DateTime.DateTime.getLocalDayNamesOfTheWeek(this.locale(), 'short');
196
+ const longDayNames = _DateTime.DateTime.getLocalDayNamesOfTheWeek(this.locale(), 'long');
197
+ return [(0, _emotion.jsx)(_AccessibleContent.AccessibleContent, {
198
+ key: 1,
199
+ alt: longDayNames[0]
200
+ }, shortDayNames[0]), (0, _emotion.jsx)(_AccessibleContent.AccessibleContent, {
201
+ key: 2,
202
+ alt: longDayNames[1]
203
+ }, shortDayNames[1]), (0, _emotion.jsx)(_AccessibleContent.AccessibleContent, {
204
+ key: 3,
205
+ alt: longDayNames[2]
206
+ }, shortDayNames[2]), (0, _emotion.jsx)(_AccessibleContent.AccessibleContent, {
207
+ key: 4,
208
+ alt: longDayNames[3]
209
+ }, shortDayNames[3]), (0, _emotion.jsx)(_AccessibleContent.AccessibleContent, {
210
+ key: 5,
211
+ alt: longDayNames[4]
212
+ }, shortDayNames[4]), (0, _emotion.jsx)(_AccessibleContent.AccessibleContent, {
213
+ key: 6,
214
+ alt: longDayNames[5]
215
+ }, shortDayNames[5]), (0, _emotion.jsx)(_AccessibleContent.AccessibleContent, {
216
+ key: 7,
217
+ alt: longDayNames[6]
218
+ }, shortDayNames[6])];
219
+ }
116
220
  renderDays() {
117
- const children = _react.Children.toArray(this.props.children);
118
- const length = children.length;
221
+ const children = this.props.children;
222
+ const childrenArr = _react.Children.toArray(children ? children : this.renderDefaultdays());
223
+ const length = childrenArr.length;
119
224
  const role = this.role === 'listbox' ? 'presentation' : void 0;
120
225
  (0, _console.logError)(length === Calendar.DAY_COUNT, `[Calendar] should have exactly ${Calendar.DAY_COUNT} children. ${length} provided.`);
121
- return children.reduce((days, day, i) => {
226
+ return childrenArr.reduce((days, day, i) => {
122
227
  const index = Math.floor(i / 7);
123
228
  if (!days[index]) days.push([]);
124
229
  days[index].push(day);
@@ -133,6 +238,68 @@ let Calendar = exports.Calendar = (_dec = (0, _emotion.withStyle)(_styles.defaul
133
238
  'aria-describedby': this._weekdayHeaderIds[i]
134
239
  }) : day))));
135
240
  }
241
+ locale() {
242
+ if (this.props.locale) {
243
+ return this.props.locale;
244
+ } else if (this.context && this.context.locale) {
245
+ return this.context.locale;
246
+ }
247
+ return _Locale.Locale.browserLocale();
248
+ }
249
+ timezone() {
250
+ if (this.props.timezone) {
251
+ return this.props.timezone;
252
+ } else if (this.context && this.context.timezone) {
253
+ return this.context.timezone;
254
+ }
255
+ return _DateTime.DateTime.browserTimeZone();
256
+ }
257
+ isDisabledDate(date) {
258
+ const disabledDates = this.props.disabledDates;
259
+ if (!disabledDates) {
260
+ return false;
261
+ }
262
+ if (Array.isArray(disabledDates)) {
263
+ for (const aDisabledDate of disabledDates) {
264
+ if (date.isSame(aDisabledDate, 'day')) {
265
+ return true;
266
+ }
267
+ }
268
+ return false;
269
+ }
270
+ return disabledDates(date.toISOString());
271
+ }
272
+ renderDefaultdays() {
273
+ const selectedDate = this.props.selectedDate;
274
+ const _this$state = this.state,
275
+ renderedDate = _this$state.renderedDate,
276
+ today = _this$state.today;
277
+ // Sets it to the first local day of the week counting back from the start of the month.
278
+ // Note that first day depends on the locale, e.g. it's Sunday in the US and
279
+ // Monday in most of the EU.
280
+ const currDate = _DateTime.DateTime.getFirstDayOfWeek(renderedDate.clone().startOf('month'));
281
+ const arr = [];
282
+ for (let i = 0; i < Calendar.DAY_COUNT; i++) {
283
+ arr.push(currDate.clone());
284
+ currDate.add({
285
+ days: 1
286
+ });
287
+ }
288
+ return arr.map(date => {
289
+ const dateStr = date.toISOString();
290
+ return (0, _emotion.jsx)(Calendar.Day, {
291
+ key: dateStr,
292
+ date: dateStr,
293
+ isSelected: selectedDate ? date.isSame(selectedDate, 'day') : false,
294
+ isToday: date.isSame(today, 'day'),
295
+ isOutsideMonth: !date.isSame(renderedDate, 'month'),
296
+ label: date.format('D MMMM YYYY') // used by screen readers
297
+ ,
298
+ onClick: this.handleDayClick,
299
+ interaction: this.isDisabledDate(date) ? 'disabled' : 'enabled'
300
+ }, date.format('DD'));
301
+ });
302
+ }
136
303
  render() {
137
304
  const passthroughProps = _View.View.omitViewProps((0, _omitProps.omitProps)(this.props, Calendar.allowedProps), Calendar);
138
305
  return (0, _emotion.jsx)(_View.View, Object.assign({}, passthroughProps, {
@@ -143,7 +310,7 @@ let Calendar = exports.Calendar = (_dec = (0, _emotion.withStyle)(_styles.defaul
143
310
  elementRef: this.handleRef
144
311
  }), this.renderHeader(), this.renderBody());
145
312
  }
146
- }, _class2.displayName = "Calendar", _class2.componentId = 'Calendar', _class2.Day = _Day.Day, _class2.DAY_COUNT = 42, _class2.propTypes = _props.propTypes, _class2.allowedProps = _props.allowedProps, _class2.defaultProps = {
313
+ }, _class2.displayName = "Calendar", _class2.componentId = 'Calendar', _class2.contextType = _ApplyLocaleContext.ApplyLocaleContext, _class2.Day = _Day.Day, _class2.DAY_COUNT = 42, _class2.propTypes = _props.propTypes, _class2.allowedProps = _props.allowedProps, _class2.defaultProps = {
147
314
  as: 'span',
148
315
  role: 'table'
149
316
  }, _class2)) || _class) || _class);
@@ -33,14 +33,20 @@ var _Day = require("./Day");
33
33
  */
34
34
 
35
35
  const propTypes = exports.propTypes = {
36
+ as: _propTypes.default.elementType,
36
37
  children: _Children.Children.oneOf([_Day.Day]),
37
- renderNextMonthButton: _propTypes.default.oneOfType([_propTypes.default.node, _propTypes.default.func]),
38
- renderPrevMonthButton: _propTypes.default.oneOfType([_propTypes.default.node, _propTypes.default.func]),
39
- renderNavigationLabel: _propTypes.default.oneOfType([_propTypes.default.node, _propTypes.default.func]),
40
- renderWeekdayLabels: _propTypes.default.arrayOf(_propTypes.default.oneOfType([_propTypes.default.node, _propTypes.default.func])).isRequired,
38
+ currentDate: _propTypes.default.string,
39
+ disabledDates: _propTypes.default.oneOfType([_propTypes.default.array, _propTypes.default.func]),
40
+ locale: _propTypes.default.string,
41
+ onDateSelected: _propTypes.default.func,
41
42
  onRequestRenderNextMonth: _propTypes.default.func,
42
43
  onRequestRenderPrevMonth: _propTypes.default.func,
43
- as: _propTypes.default.elementType,
44
- role: _propTypes.default.oneOf(['table', 'listbox'])
44
+ renderNavigationLabel: _propTypes.default.oneOfType([_propTypes.default.node, _propTypes.default.func]),
45
+ renderNextMonthButton: _propTypes.default.oneOfType([_propTypes.default.node, _propTypes.default.func]),
46
+ renderPrevMonthButton: _propTypes.default.oneOfType([_propTypes.default.node, _propTypes.default.func]),
47
+ renderWeekdayLabels: _propTypes.default.arrayOf(_propTypes.default.oneOfType([_propTypes.default.node, _propTypes.default.func])),
48
+ role: _propTypes.default.oneOf(['table', 'listbox']),
49
+ selectedDate: _propTypes.default.string,
50
+ timezone: _propTypes.default.string
45
51
  };
46
- const allowedProps = exports.allowedProps = ['children', 'renderNextMonthButton', 'renderPrevMonthButton', 'renderNavigationLabel', 'renderWeekdayLabels', 'onRequestRenderNextMonth', 'onRequestRenderPrevMonth', 'as', 'role'];
52
+ const allowedProps = exports.allowedProps = ['as', 'children', 'currentDate', 'disabledDates', 'locale', 'onDateSelected', 'onRequestRenderNextMonth', 'onRequestRenderPrevMonth', 'renderNavigationLabel', 'renderNextMonthButton', 'renderPrevMonthButton', 'renderWeekdayLabels', 'role', 'selectedDate', 'timezone'];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@instructure/ui-calendar",
3
- "version": "8.51.0",
3
+ "version": "8.51.1-snapshot-5",
4
4
  "description": "A calendar component.",
5
5
  "author": "Instructure, Inc. Engineering and Product Design",
6
6
  "module": "./es/index.js",
@@ -23,25 +23,29 @@
23
23
  },
24
24
  "license": "MIT",
25
25
  "devDependencies": {
26
- "@instructure/ui-babel-preset": "8.51.0",
27
- "@instructure/ui-color-utils": "8.51.0",
28
- "@instructure/ui-test-locator": "8.51.0",
29
- "@instructure/ui-test-utils": "8.51.0",
30
- "@instructure/ui-themes": "8.51.0"
26
+ "@instructure/ui-babel-preset": "8.51.1-snapshot-5",
27
+ "@instructure/ui-color-utils": "8.51.1-snapshot-5",
28
+ "@instructure/ui-test-locator": "8.51.1-snapshot-5",
29
+ "@instructure/ui-test-utils": "8.51.1-snapshot-5",
30
+ "@instructure/ui-themes": "8.51.1-snapshot-5",
31
+ "@testing-library/jest-dom": "^6.1.4",
32
+ "@testing-library/react": "^14.0.0"
31
33
  },
32
34
  "dependencies": {
33
35
  "@babel/runtime": "^7.23.2",
34
- "@instructure/console": "8.51.0",
35
- "@instructure/emotion": "8.51.0",
36
- "@instructure/shared-types": "8.51.0",
37
- "@instructure/ui-a11y-content": "8.51.0",
38
- "@instructure/ui-i18n": "8.51.0",
39
- "@instructure/ui-prop-types": "8.51.0",
40
- "@instructure/ui-react-utils": "8.51.0",
41
- "@instructure/ui-testable": "8.51.0",
42
- "@instructure/ui-utils": "8.51.0",
43
- "@instructure/ui-view": "8.51.0",
44
- "@instructure/uid": "8.51.0",
36
+ "@instructure/console": "8.51.1-snapshot-5",
37
+ "@instructure/emotion": "8.51.1-snapshot-5",
38
+ "@instructure/shared-types": "8.51.1-snapshot-5",
39
+ "@instructure/ui-a11y-content": "8.51.1-snapshot-5",
40
+ "@instructure/ui-buttons": "8.51.1-snapshot-5",
41
+ "@instructure/ui-i18n": "8.51.1-snapshot-5",
42
+ "@instructure/ui-icons": "8.51.1-snapshot-5",
43
+ "@instructure/ui-prop-types": "8.51.1-snapshot-5",
44
+ "@instructure/ui-react-utils": "8.51.1-snapshot-5",
45
+ "@instructure/ui-testable": "8.51.1-snapshot-5",
46
+ "@instructure/ui-utils": "8.51.1-snapshot-5",
47
+ "@instructure/ui-view": "8.51.1-snapshot-5",
48
+ "@instructure/uid": "8.51.1-snapshot-5",
45
49
  "prop-types": "^15.8.1"
46
50
  },
47
51
  "peerDependencies": {
@@ -4,6 +4,57 @@ describes: Calendar
4
4
 
5
5
  The `Calendar` component provides a visual interface for date data.
6
6
 
7
+ ### Default config
8
+
9
+ For ease of use in most situations, the `Calendar` component provides a default
10
+ configuration. The default configuration can be overridden by providing props
11
+ to the `Calendar` component.
12
+
13
+ ```js
14
+ ---
15
+ type: example
16
+ ---
17
+ <Calendar locale="hu"/>
18
+ ```
19
+
20
+ ### Default config with additional props
21
+
22
+ - ```js
23
+ class Example extends React.Component {
24
+ state = {
25
+ selectedDate: ''
26
+ }
27
+ render = () => (
28
+ <Calendar
29
+ currentDate="2023-12-15"
30
+ disabledDates={['2023-12-22', '2023-12-12', '2023-12-11']}
31
+ selectedDate={this.state.selectedDate}
32
+ onDateSelected={(date) => {
33
+ this.setState({ selectedDate: date })
34
+ }}
35
+ />
36
+ )
37
+ }
38
+ render(<Example />)
39
+ ```
40
+
41
+ - ```js
42
+ const Example = () => {
43
+ const [selectedDate, setSelectedDate] = useState('')
44
+ return (
45
+ <Calendar
46
+ currentDate="2023-12-15"
47
+ disabledDates={['2023-12-22', '2023-12-12', '2023-12-11']}
48
+ selectedDate={selectedDate}
49
+ onDateSelected={(date) => {
50
+ setSelectedDate(date)
51
+ }}
52
+ />
53
+ )
54
+ }
55
+ render(<Example />)
56
+ ```
57
+
7
58
  ### Composing a Calendar in your Application
8
59
 
9
60
  By design, the `Calendar` component does not dictate which date libraries or
@@ -0,0 +1,83 @@
1
+ /*
2
+ * The MIT License (MIT)
3
+ *
4
+ * Copyright (c) 2015 - present Instructure, Inc.
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ */
24
+ import React from 'react'
25
+ import { render, screen } from '@testing-library/react'
26
+
27
+ import '@testing-library/jest-dom'
28
+ import Calendar from '../index'
29
+
30
+ describe('<Calendar />', () => {
31
+ describe('with minimal config', () => {
32
+ it('should render 44 buttons without config', async () => {
33
+ render(<Calendar />)
34
+ const buttons = document.getElementsByTagName('button')
35
+ expect(buttons.length).toEqual(44)
36
+ })
37
+ it('should render proper week names by default', async () => {
38
+ const { container } = render(<Calendar />)
39
+ const thead = container.querySelector('thead')
40
+ expect(thead).toHaveTextContent(
41
+ 'SundaySuMondayMoTuesdayTuWednesdayWeThursdayThFridayFrSaturdaySa'
42
+ )
43
+ })
44
+ it('should render proper week names if locale is set', async () => {
45
+ const { container } = render(<Calendar locale="hu" />)
46
+ const thead = container.querySelector('thead')
47
+ expect(thead).toHaveTextContent(
48
+ 'hétfőhkeddkszerdaszecsütörtökcspéntekpszombatszovasárnapv'
49
+ )
50
+ })
51
+ it('should disable days properly', async () => {
52
+ const { container } = render(
53
+ <Calendar
54
+ currentDate="2023-12-15"
55
+ disabledDates={['2023-12-22', '2023-12-12', '2023-12-11']}
56
+ />
57
+ )
58
+ const buttons = container.querySelectorAll('button[disabled]')
59
+
60
+ const disabledTexts = [
61
+ '11 December 202311',
62
+ '12 December 202312',
63
+ '22 December 202322'
64
+ ]
65
+ buttons.forEach((button, index) => {
66
+ expect(button).toHaveTextContent(disabledTexts[index])
67
+ })
68
+ })
69
+ it('should indicate selected day', async () => {
70
+ render(<Calendar currentDate="2023-12-15" selectedDate="2023-12-22" />)
71
+
72
+ const selectedDay =
73
+ screen.queryByText('22 December 2023')?.parentElement?.parentElement
74
+
75
+ expect(selectedDay).toBeDefined()
76
+ if (selectedDay) {
77
+ expect(window.getComputedStyle(selectedDay)?.background).toBe(
78
+ 'rgb(11, 135, 75)'
79
+ )
80
+ }
81
+ })
82
+ })
83
+ })