├── .gitignore
├── .npmignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── _prev.tar.gz
├── arredemo.json
├── demo
├── README.md
├── index.html
├── index.js
└── src
│ ├── Demo.js
│ ├── demo.scss
│ ├── rdp.js
│ └── samples
│ ├── RDPBasic.js
│ ├── RDPBasicDisabled.js
│ ├── RDPBasicFocusBlur.js
│ ├── RDPCustomClear.js
│ ├── RDPCustomContainer.js
│ ├── RDPCustomFormControl.js
│ ├── RDPCustomFormat.js
│ ├── RDPCustomInputGroup.js
│ ├── RDPCustomPickMonth.js
│ ├── RDPCustomPickMonthDefault.js
│ ├── RDPCustomPrevNext.js
│ ├── RDPCustomWeek.js
│ ├── RDPPlacementBottom.js
│ ├── RDPPlacementLeft.js
│ ├── RDPPlacementRight.js
│ ├── RDPPlacementTop.js
│ ├── RDPSizeLarge.js
│ ├── RDPSizeSmall.js
│ ├── RDPValidityInvalid.js
│ └── RDPValidityValid.js
├── logo
├── favicon
│ └── reactstrap-date-picker.ico
└── reactstrap-date-picker.png
├── package.json
├── patches
├── react-transition-group+4.4.5.patch
└── reactstrap+9.2.3.patch
├── playground
├── check
│ └── index.html
├── current
│ └── index.html
├── future
│ ├── future_build.sh
│ ├── index.html
│ └── package.json
└── gh_issue.html
├── src
├── DatePicker.mjs
├── calendar
│ ├── Calendar.mjs
│ ├── CalendarBody.mjs
│ ├── CalendarDayInMonth.mjs
│ ├── CalendarDayOutOfMonth.mjs
│ ├── CalendarFooter.mjs
│ ├── CalendarHeader.mjs
│ ├── CalendarSubHeader.mjs
│ ├── CalendarWeekNum.mjs
│ ├── pickmonth
│ │ └── PickMonthDefault.mjs
│ ├── useCalendarDays.mjs
│ └── useCalendarProps.mjs
├── index.mjs
├── input
│ ├── InputClearButton.mjs
│ ├── InputControlInput.mjs
│ ├── InputGroup.mjs
│ ├── InputHidden.mjs
│ ├── InputOverlay.mjs
│ ├── useCustomEvents.mjs
│ ├── useDayLabels.mjs
│ ├── useInputIds.mjs
│ └── useInputValues.mjs
├── props.tar.gz
└── util
│ ├── compareMonths.mjs
│ ├── getDateFromIsoString.mjs
│ ├── getInstanceCount.mjs
│ ├── getIsoStringFromDate.mjs
│ ├── getMaybeFuncValue.mjs
│ ├── setTimeToNoon.mjs
│ ├── useCheckProps.mjs
│ └── useMaybeFuncProp.mjs
├── test
├── README.md
├── before.mjs
├── esm_pkg.cjs
├── tools
│ ├── checks.cjs
│ └── finders.cjs
└── units
│ ├── integrity
│ ├── basic.cjs
│ ├── calendar.cjs
│ └── typing.cjs
│ └── properties
│ ├── calendar
│ ├── calendarContainer.cjs
│ ├── calendarPlacement.cjs
│ ├── dayLabels.cjs
│ ├── monthLabels.cjs
│ ├── nextButtonElement.cjs
│ ├── pickMonthElement.cjs
│ ├── previousButtonElement.cjs
│ ├── roundedCorners.cjs
│ ├── showTodayButton.cjs
│ └── weekStartsOn.cjs
│ ├── events
│ ├── changes.cjs
│ └── focus.cjs
│ ├── globals
│ ├── clearButtonElement.cjs
│ ├── dateFormat.cjs
│ ├── defaultValue.cjs
│ └── minMaxDate.cjs
│ ├── input
│ ├── (in)valid.cjs
│ ├── autoFocus.cjs
│ ├── className.cjs
│ ├── customControl.cjs
│ ├── disabled.cjs
│ ├── inputRef.cjs
│ └── style.cjs
│ └── inputGroup
│ └── customInputGroup.cjs
└── xeira.json
/.gitignore:
--------------------------------------------------------------------------------
1 | ### SublimeText ###
2 | *.sublime-workspace
3 |
4 | ### OSX ###
5 | .DS_Store
6 | .AppleDouble
7 | .LSOverride
8 | Icon
9 |
10 | # Thumbnails
11 | ._*
12 |
13 | # Files that might appear on external disk
14 | .Spotlight-V100
15 | .Trashes
16 |
17 | ### Windows ###
18 | # Windows image file caches
19 | Thumbs.db
20 | ehthumbs.db
21 |
22 | # Folder config file
23 | Desktop.ini
24 |
25 | # Recycle Bin used on file shares
26 | $RECYCLE.BIN/
27 |
28 | # App specific
29 | coverage
30 | node_modules
31 | bower_components
32 | .tmp
33 | lib
34 | dist
35 | npm-debug.log*
36 | *.sublime-project
37 | package-lock.json
38 | TODO.lst
39 | .vscode
40 | test/bundle.js
41 |
42 | arredemo
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | src
2 | test
3 | tests
4 | demo
5 | Procfile
6 | arredemo
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 |
2 | # Changelog
3 |
4 | Originally based on [react-bootstrap-date-picker](https://github.com/pushtell/react-bootstrap-date-picker/),
5 | `reactstrap-date-picker` has evolved. From v1.0 it has been refactored, using `react` hooks,
6 | with cleaner code and an improved final performance.
7 |
8 | ## 2.0.0-beta.2
9 |
10 | * Upgraded `xeira`
11 |
12 | ## 2.0.0-beta.1
13 |
14 | * Upgraded versions to:
15 | - `react@^18.3.1`
16 | - `reactstrap@^9.2.3`
17 | - `bootstrap@^5.1.0`
18 | * Now using [`xeira`](https://github.com/afialapis/xeira) for bundling. Forced to rewrite tests using `React Testing Library`.
19 | * Removed `prop-types` usages. Also patched some `reactstrap` warning about it.
20 | * Removed `defaultProps` usages. Also patched some `reactstrap` warning about it.
21 |
22 | ## 1.0.11
23 |
24 | * fixed `calendarContainer` prop causes calendar to close unexpectedly
25 |
26 | ## 1.0.10
27 |
28 | * fixed `onClear` event: if passed, `onChange` is not fired
29 |
30 | ## 1.0.9
31 |
32 | * fixed blur handle when navigating months
33 |
34 | ## 1.0.8
35 |
36 | * fixed `inputRef` property to make it work properly when passing callback refs
37 | * keep Calendar open when clicking inside the control input
38 | * improve bad format handling on blur
39 |
40 | ## 1.0.6
41 |
42 | * cleaner readme
43 |
44 | ## 1.0.5
45 |
46 | * fix valid props on hidden input
47 |
48 | ## 1.0.4
49 |
50 | * fix warning on `prop-types`
51 |
52 | ## 1.0.3
53 |
54 | * Added [pickMonthElement](https://github.com/afialapis/reactstrap-date-picker/issues/22)
55 |
56 | ## 1.0.2
57 |
58 | * Fixed [issue #20: In/valid props doesn't apply the reactstrap in/valid css style](https://github.com/afialapis/reactstrap-date-picker/issues/20)
59 |
60 | ## 1.0.1
61 |
62 | * Fixed [issue #19: ReferenceError: Element is not defined](https://github.com/afialapis/reactstrap-date-picker/issues/19)
63 |
64 | ## 1.0.0
65 |
66 | * Introduction of `react` Hooks
67 | * Deep refactor of the source code
68 | * Supported versions:
69 | - `react` >= 16.13.1
70 | - `reactstrap` >= 8.5.1
71 | - `bootstrap` >= 4.5.2
72 | * Improved performance
73 | * Smaller bundle sizes
74 |
75 | ## 0.0.16
76 |
77 | * Version to use if you wanna go `reactstrap` 9
78 | * Supported versions:
79 | - `react` >= 14
80 | - `reactstrap` 9.0.1
81 | - `bootstrap` 5.1.3
82 |
83 | ## 0.0.12
84 |
85 | * Fixed [issue #15: placeholder will not fallback to dateFormat](https://github.com/afialapis/reactstrap-date-picker/issues/15)
86 | * Fixed [issue #16. do not allow keyboard input of dates out of minDate/maxDate](https://github.com/afialapis/reactstrap-date-picker/issues/16)
87 | * Supported versions:
88 | - `react` >= 14
89 | - `reactstrap` 8.5.1
90 | - `bootstrap` 4.5.2
91 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 afialapis.com
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # reactstrap-date-picker
4 | [](https://www.npmjs.com/package/reactstrap-date-picker)
5 | [](https://www.npmjs.com/package/reactstrap-date-picker)
6 |
7 | 
8 |
9 | # Intro
10 |
11 | A Reactstrap based, zero dependencies, date picker.
12 |
13 | Demo and docs at [reactstrap-date-picker](https://reactstrap-date-picker.afialapis.com/).
14 |
15 | # Table of Contents
16 |
17 | 1. [Installation](#installation)
18 | 2. [Usage](#usage)
19 | 3. [API Reference](#api-reference)
20 | 4. [Deeper customizing](#deeper-customizing)
21 | 5. [Inspect this package](#inspect-this-package)
22 | 6. [Changelog](#changelog)
23 |
24 |
25 | # Installation
26 |
27 | Using `npm`:
28 |
29 | ```bash
30 | npm install reactstrap-date-picker
31 | ```
32 |
33 | `reactstrap-date-picker` works with these [peer dependencies](https://nodejs.org/en/blog/npm/peer-dependencies/):
34 | * [React](https://github.com/facebook/react) ^18.3.1
35 | * [Reactstrap](https://github.com/reactstrap/reactstrap) ^9.2.3
36 | * [Bootstrap](https://github.com/twbs/bootstrap) ^5.1.0
37 |
38 | Check [Changelog](#changelog) for more info on other versions.
39 |
40 |
41 | # Usage
42 |
43 | ```js
44 | import React, {useState, useEffect} from 'react
45 | import {FormGroup, Label, FormText} from 'reactstrap'
46 | import {DatePicker} from 'reactstrap-date-picker'
47 |
48 | const App = () => {
49 | const [value, setValue]= useState(new Date().toISOString())
50 | const [fmtValue, setFmtValue]= useState(undefined)
51 |
52 | handleChange(value, formattedValue) {
53 | setValue(value)
54 | setFmtValue(formattedValue)
55 | }
56 |
57 | useEffect(( )=> {
58 | console.log(`Formatted value is ${fmtValue}`)
59 | }, [fmtValue])
60 |
61 | return (
62 |
63 | My Date Picker
64 | handleChange(v, f)} />
67 | Help
68 |
69 | )
70 | }
71 | ```
72 |
73 |
74 | # API Reference
75 |
76 | ## ` `
77 |
78 | `reactstrap-date-picker`'s public component.
79 |
80 | ```js
81 | import {DatePicker} from 'reactstrap-date-picker'
82 |
83 | const Example = () => {
84 | ...
85 | return (
86 | ...
87 |
88 | ...
89 | )
90 | }
91 |
92 | ```
93 |
94 |
95 | ## Global properties
96 |
97 |
98 |
99 | value, defaultValue, id, name, dateFormat, minDate, maxDate, showClearButton, clearButtonElement
100 |
101 |
102 |
103 | ### `value`
104 |
105 | ISO date string representing the current value. Cannot be set alongside `defaultValue`.
106 |
107 | * Optional
108 | * Type: `string`.
109 | * Example: `"2016-05-19T12:00:00.000Z"`
110 |
111 | ### `defaultValue`
112 |
113 | ISO date string representing the default value. Cannot be set alongside `value`.
114 |
115 | * Optional
116 | * Type: `string`
117 | * Example: `"2016-05-19T12:00:00.000Z"`
118 |
119 | ### `id`
120 |
121 | HTML identifier for the `reactstrap-date-picker`'s input (the hidden one). You may
122 | want to use it in case you need to traverse somehow the DOM.
123 |
124 | * Optional
125 | * Type: `string`.
126 | * Example: `"example-datepicker"`
127 |
128 | ### `name`
129 |
130 | HTML `name` attribute for the `reactstrap-date-picker`'s input (the hidden one). You may
131 | need to use it depending on how your handle your Forms.
132 |
133 | * Optional
134 | * Type: `string`.
135 | * Example: `"date-field"`
136 |
137 | ### `dateFormat`
138 |
139 | Date format. Any combination of DD, MM, YYYY and separator.
140 |
141 | * Optional
142 | * Type: `string`
143 | * Examples: `"MM/DD/YYYY"`, `"YYYY/MM/DD"`, `"MM-DD-YYYY"`, or `"DD MM YYYY"`
144 |
145 | ### `minDate`
146 |
147 | ISO date string to set the lowest allowable date value.
148 |
149 | * Optional
150 | * Type: `string`
151 | * Example: `"2016-05-19T12:00:00.000Z"`
152 |
153 | ### `maxDate`
154 |
155 | ISO date string to set the highest allowable date value.
156 |
157 | * Optional
158 | * Type: `string`
159 | * Example: `"2016-05-19T12:00:00.000Z"`
160 |
161 | ### `showClearButton`
162 |
163 | Toggles the visibility of the clearButton
164 |
165 | * Optional
166 | * Type: `bool`
167 | * Default: `false`
168 |
169 | ### `clearButtonElement`
170 |
171 | Character or component to use for the clear button.
172 |
173 | * Optional
174 | * Type: `string` or `ReactClass`
175 | * Default: `"×"`
176 |
177 |
178 |
179 |
180 | ## Input properties
181 |
182 |
183 | autoComplete, autoFocus, disabled, noValidate, placeholder, required, className, style, inputRef, customControl, children
184 |
185 |
186 |
187 | ### `autoComplete`
188 |
189 | Hint for form autofill feature.
190 |
191 | * Optional
192 | * Type: `string`
193 | * Default: `on`
194 |
195 | ### `autoFocus`
196 |
197 | Whether or not component starts with focus.
198 |
199 | * Optional
200 | * Type: `bool`
201 | * Default: `false`
202 |
203 | ### `disabled`
204 |
205 | Whether or not component is disabled.
206 |
207 | * Optional
208 | * Type: `bool`
209 | * Default: `false`
210 |
211 | ### `noValidate`
212 |
213 | When present, it specifies that the form-data (input) should not be validated when submitted.
214 |
215 | * Optional
216 | * Type: `bool`
217 | * Default: `false`
218 |
219 | ### `placeholder`
220 |
221 | Text that appears in the form control when it has no value set.
222 |
223 | * Optional
224 | * Type: `text`
225 | * Example: `John Doe`
226 |
227 | ### `required`
228 |
229 | `boolean`. A value is required or must be check for the form to be submittable
230 |
231 | * Optional
232 | * Type: `boolean`
233 | * Default: `false`
234 |
235 | ### `className`
236 |
237 | Class name passed to the Form Control input element.
238 |
239 | * Optional
240 | * Type: `string`
241 | * Example: `example-class`
242 |
243 | ### `style`
244 |
245 | Style object passed to the Form Control input element.
246 |
247 | * Optional
248 | * Type: `object`
249 | * Example: `{width: "100%"}`
250 |
251 | ### `inputRef`
252 |
253 | A React ref to the Form Control input element
254 |
255 | * Optional
256 | * Type: `ref`
257 |
258 | ### `customControl`
259 |
260 | Overwrite the default Form Control component with your own component.
261 |
262 | * Optional
263 | * Type: `React.Component`
264 | * Example: ` `
265 |
266 | ### `children`
267 |
268 | `children` elements from the Form Control`
269 |
270 | * Optional
271 | * Type: `React.Component`
272 |
273 |
274 |
275 |
276 | ## Input Group properties
277 |
278 |
279 |
280 | size, valid, invalid, customInputGroup
281 |
282 |
283 |
284 | ### `size`
285 |
286 | Size of the input
287 |
288 | * Optional
289 | * Type: `string`
290 | * Examples: `lg`, `sm`, ...
291 |
292 | You can also override it completely and pass your own component:
293 |
294 | ### `valid`
295 |
296 | Applies the `is-valid` class when `true`, does nothing when `false`
297 |
298 | * Optional
299 | * Type: `bool`
300 | * Example: `true`
301 |
302 | ### `invalid`
303 |
304 | Applies the `is-invalid` class when `true`, does nothing when `false`
305 |
306 | * Optional
307 | * Type: `bool`
308 | * Example: `true`
309 |
310 | ### `customInputGroup`
311 |
312 | Overwrite the default InputGroup component with your own component.
313 |
314 | * Optional
315 | * Type: `React.Component`
316 | * Example: ` `
317 |
318 |
319 |
320 | ## Calendar properties
321 |
322 |
323 |
324 | dayLabels, monthLabels, weekStartsOn, showWeeks, pickMonthElement, previousButtonElement, nextButtonElement, showTodayButton, todayButtonLabel, cellPadding, roundedCorners, calendarPlacement, calendarContainer
325 |
326 |
327 |
328 | ### `dayLabels`
329 |
330 | Array of day names to use in the calendar. Starting on Sunday.
331 |
332 | * Optional
333 | * Type: `array`
334 | * Default: `['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']`
335 |
336 | ### `monthLabels`
337 |
338 | Array of month names to use in the calendar.
339 |
340 | * Optional
341 | * Type: `array`
342 | * Default: `['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']`
343 |
344 | ### `weekStartsOn`
345 |
346 | Makes the calendar's week to start on a specified day. 0 = Sunday, 1 = Monday, etc.
347 |
348 | * Optional
349 | * Type: `number`
350 | * Example: `4`
351 |
352 | ### `showWeeks`
353 |
354 | Shows the number of the week in the calendar
355 |
356 | * Optional
357 | * Type: `bool`
358 | * Default: `false`
359 |
360 | ### `pickMonthElement`
361 |
362 | Optional component to use for the calendar's year and month pickers.
363 |
364 | * Optional
365 | * Type: `string` or `ReactClass`
366 | * Default: `undefined`
367 |
368 | `pickMonthElement = undefined` is the same as `pickMonthElement = "none"`.
369 |
370 | #### custom pickMonthElement
371 |
372 | You can pass a custom `React` component, which will receive these properties:
373 | - `displayDate`
374 | - `minDate`
375 | - `maxDate`
376 | - `onChangeMonth`: a callback receiving an `int` parameter (month number)
377 | - `onChangeYear`: a callback receiving an `int` parameter (year number)
378 |
379 | On the [demo](https://github.com/afialapis/reactstrap-date-picker/blob/master/demo/src/samples/RDPCustomPickMonth.js)
380 | you will find a simple custom element.
381 |
382 |
383 | #### `default` pickMonthElement
384 |
385 | There is a predefined component, consisting of two simple `select` elements,
386 | which can be used by passing `pickMonthElement = "default"`.
387 |
388 | It has a simple styling, which may not fit your needs. Maybe you can tweak it
389 | through the `css` classes used by `reactstrap-date-picker`:
390 |
391 | ```html
392 |
403 | ```
404 |
405 |
406 | ### `previousButtonElement`
407 |
408 | Character or component to use for the calendar's previous button.
409 |
410 | * Optional
411 | * Type: `string` or `ReactClass`
412 | * Default: `"<"`
413 |
414 | ### `nextButtonElement`
415 |
416 | Character or component to use for the calendar's next button.
417 |
418 | * Optional
419 | * Type: `string` or `ReactClass`
420 | * Default: `">"`
421 |
422 | ### `showTodayButton`
423 |
424 | Toggles the visibility of the today-button.
425 |
426 | * Optional
427 | * Type: `boolean`
428 | * Default: `false`
429 |
430 | ### `todayButtonLabel`
431 |
432 | Label for the today-button
433 |
434 | * Optional
435 | * Type: `string`
436 | * Default: `"Today"`
437 |
438 | ### `cellPadding`
439 |
440 | CSS padding value for calendar date cells.
441 |
442 | * Optional
443 | * Type: `string`
444 | * Default: `"5px"`
445 |
446 | ### `roundedCorners`
447 |
448 | CSS border-radius value for calendar date cells.
449 |
450 | * Optional
451 | * Type: `bool`
452 | * Default: `false`
453 |
454 | ### `calendarPlacement`
455 |
456 | Overlay placement for the popover calendar.
457 |
458 | * Optional
459 | * Type: `string` or `function`
460 | * Default: `"top"`
461 |
462 | ### `calendarContainer`
463 |
464 | Overlay container for the popover calendar. When placing the `reactstrap-date-picker` in a scrolling container, set this prop to some ancestor of the scrolling container.
465 |
466 | * Optional
467 | * Type: A DOM element, a string selector or a `ref`
468 | * Example: `document.body`
469 |
470 |
471 |
472 |
473 | ## Event properties
474 |
475 |
476 | onChange, onClear, onFocus, onBlur, onInvalid
477 |
478 |
479 |
480 | ### `onChange`
481 |
482 | Change callback function.
483 |
484 | * Optional
485 | * Type: `function`
486 | * Callback Arguments:
487 | * `value` : ISO date string representing the selected value.
488 | * Type: `String`
489 | * Example: `"2016-05-19T12:00:00.000Z"`
490 | * `formattedValue` : String representing the formatted value as defined by the `dateFormat` property.
491 | * Type: `String`
492 | * Example: `"05/19/2016"`
493 |
494 | ### `onClear`
495 |
496 | Defines what happens when clear button is clicked.
497 |
498 | * Optional
499 | * Type: `function`
500 |
501 | If passed, `onChange` event won't be fired when clicking clear button. This way, you will be able to customize
502 | the input behavior, for example:
503 |
504 | ```jsx
505 | {
507 | const today= new Date()
508 | setValue(today.toISOString())
509 | }}
510 | />
511 | ```
512 |
513 | ### `onFocus`
514 |
515 | Focus callback function.
516 |
517 | * Optional
518 | * Type: `function`
519 | * Callback Arguments:
520 | * `event` : Focus event.
521 | * Type: `Event`
522 |
523 | ### `onBlur`
524 |
525 | Blur callback function.
526 |
527 | * Optional
528 | * Type: `function`
529 | * Callback Arguments:
530 | * `event` : Blur event.
531 | * Type: `Event`
532 |
533 | ### `onInvalid`
534 |
535 | Defines what happens when input has not passed the form validation.
536 |
537 | * Optional
538 | * Type: `function`
539 |
540 |
541 |
542 |
543 | # Deeper customizing
544 |
545 |
546 |
547 | Customize styling directly trough CSS.
548 |
549 |
550 |
551 | You can also customize `reactstrap-date-picker` using `CSS`, trough element's `id` or `class` attributes.
552 |
553 | `reactstrap-date-picker` renders several elements, all contained within a [reactstrap InputGroup](https://reactstrap.github.io/?path=/docs/components-inputgroup--input-group).
554 | Such elements will have its unique `id` attribute, plus `reactstrap-date-picker` custom `class` names (prefixed by `rdp-*`).
555 |
556 | The rendered DOM structure seems like this:
557 |
558 | ```html
559 |
593 | ```
594 |
595 | This `SUFFIX` is:
596 |
597 | - `props.name`
598 |
599 | - if `props.name` is not passed, then use `props.id`
600 |
601 | - if `props.id` is not passed, then take a global counter of active `reactstrap-date-picker` instances
602 |
603 | So, the idea is, depending on your needs:
604 |
605 | - if you don't need handle `id`s at all, `reactstrap-date-picker` will render unique `id` with no problem
606 |
607 | - if you need a basic `id` usage, for example accessing the `reactstrap-date-picker`'s value from the DOM, then
608 | you just have to pass `props.id` and get the value from the element with that `id`
609 |
610 | - if you will perform more complex operations, then use `props.name` or `props.id`, and pay attention to the
611 | previous DOM structure and the `SUFFIX` presences
612 |
613 |
614 |
615 |
616 | # Inspect this package
617 |
618 | ## Demo
619 |
620 | ```bash
621 |
622 | npm run demo
623 |
624 | ```
625 |
626 | And visit [http://localhost:8003](http://localhost:8003) on your browser
627 |
628 |
629 | ## Running Tests
630 |
631 | ```bash
632 |
633 | npm run test
634 |
635 | ```
636 |
637 | # Changelog
638 |
639 | See [changelog here](https://github.com/afialapis/reactstrap-date-picker/blob/master/CHANGELOG.md)
640 |
--------------------------------------------------------------------------------
/_prev.tar.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/afialapis/reactstrap-date-picker/8be567d29eee1dfe43c80524e7463b6ca9ea721f/_prev.tar.gz
--------------------------------------------------------------------------------
/arredemo.json:
--------------------------------------------------------------------------------
1 | {
2 | "theme": "default",
3 | "favicon": "logo/favicon/reactstrap-date-picker.ico",
4 | "logo": "logo/reactstrap-date-picker.png",
5 | "url": "https://reactstrap-date-picker.afialapis.com/",
6 | "company": "Afialapis",
7 | "company_url": "https://www.afialapis.com",
8 | "doc_versions": ["1.0.11", "2.0.0-beta.2"],
9 | "md": {
10 | "strip_details_tag": true,
11 | "keep_summary_content": false
12 | },
13 | "demo_entry": "demo/src/Demo.js"
14 | }
15 |
--------------------------------------------------------------------------------
/demo/README.md:
--------------------------------------------------------------------------------
1 | # Run this demo
2 |
3 | 1. Clone the [reactstrap-date-picker repository](https://github.com/afialapis/reactstrap-date-picker)
4 | 2. Run `npm install` to install dependencies
5 | 3. Run `npm run demo`
6 | 4. Open [http://localhost:3010](http://localhost:3010) in your browser
7 | 5. Play with it!
--------------------------------------------------------------------------------
/demo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | reactstrap-date-picker demo
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/demo/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {createRoot} from 'react-dom/client'
3 |
4 | import Demo from './src/Demo'
5 |
6 | const container = document.getElementById('content')
7 | const root = createRoot(container)
8 | root.render( )
--------------------------------------------------------------------------------
/demo/src/Demo.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Container, Row, Col } from 'reactstrap'
3 | import RDPBasic from './samples/RDPBasic'
4 | import RDPBasicDisabled from './samples/RDPBasicDisabled'
5 | import RDPCustomFormat from './samples/RDPCustomFormat'
6 | import RDPCustomClear from './samples/RDPCustomClear'
7 | import RDPCustomPrevNext from './samples/RDPCustomPrevNext'
8 | import RDPCustomPickMonth from './samples/RDPCustomPickMonth'
9 | import RDPCustomPickMonthDefault from './samples/RDPCustomPickMonthDefault'
10 | import RDPCustomWeek from './samples/RDPCustomWeek'
11 | import RDPFocusBlur from './samples/RDPBasicFocusBlur'
12 | import RDPSizeSmall from './samples/RDPSizeSmall'
13 | import RDPSizeLarge from './samples/RDPSizeLarge'
14 | import RDPPlacementTop from './samples/RDPPlacementTop'
15 | import RDPPlacementBottom from './samples/RDPPlacementBottom'
16 | import RDPPlacementLeft from './samples/RDPPlacementLeft'
17 | import RDPPlacementRight from './samples/RDPPlacementRight'
18 | import RDPCustomInputGroup from './samples/RDPCustomInputGroup'
19 | import RDPCustomFormControl from './samples/RDPCustomFormControl'
20 | import RDPCustomContainer from './samples/RDPCustomContainer'
21 | import RDPValidityValid from './samples/RDPValidityValid'
22 | import RDPValidityInvalid from './samples/RDPValidityInvalid'
23 |
24 | import '../../node_modules/bootstrap/dist/css/bootstrap.min.css'
25 | import './demo.scss'
26 |
27 | const Title = ({title}) =>
28 |
29 |
30 |
31 | {title}
32 |
33 |
34 |
35 |
36 | const Pair = ({one, two}) =>
37 |
38 |
39 |
40 |
41 | {one()}
42 |
43 |
44 | {two()}
45 |
46 |
47 |
48 |
49 |
50 | const Three = ({one, two, three}) =>
51 |
52 |
53 |
54 |
55 | {one()}
56 |
57 |
58 | {two()}
59 |
60 |
61 | {three()}
62 |
63 |
64 |
65 |
66 |
67 | const Four = ({one, two, three, four}) =>
68 |
69 |
70 |
71 |
72 | {one()}
73 |
74 |
75 | {two()}
76 |
77 |
78 | {three()}
79 |
80 |
81 | {four()}
82 |
83 |
84 |
85 |
86 |
87 |
88 | const Demo = () => {
89 | return (
90 |
91 |
92 |
93 |
94 |
95 |
96 | Reactstrap Date Picker demo
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 | {/**/}
122 |
123 |
124 |
125 | );
126 | }
127 |
128 |
129 | export default Demo;
--------------------------------------------------------------------------------
/demo/src/demo.scss:
--------------------------------------------------------------------------------
1 | h1 {
2 | text-align: center;
3 | margin-top: 2em;
4 | font-size: 2em;
5 | }
6 |
7 | h2 {
8 | font-size: 1.5em;
9 | font-style: italic;
10 | }
11 |
12 |
13 | body {
14 | padding-bottom: 50px;
15 | }
16 | .row {
17 | margin-bottom: 1em;
18 | }
--------------------------------------------------------------------------------
/demo/src/rdp.js:
--------------------------------------------------------------------------------
1 | import {DatePicker} from '../../src'
2 |
3 | export {DatePicker}
--------------------------------------------------------------------------------
/demo/src/samples/RDPBasic.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useRef } from 'react'
2 | import {
3 | FormGroup,
4 | FormText,
5 | Label
6 | } from 'reactstrap'
7 | import {DatePicker} from '../rdp'
8 |
9 | const RDPBasic = () => {
10 | const ref = useRef()
11 |
12 | const inputName = 'reactstrap_date_picker_basic'
13 | const [value, setValue] = useState("2019-06-01T00:00:00.000Z")
14 | const [fmtValue, setFmtValue] = useState("06/01/2019")
15 |
16 |
17 | //const [value, setValue] = useState("2017-07-21T00:00:00.000Z")
18 | //const [fmtValue, setFmtValue] = useState("07/21/2017")
19 | //const minDate = "2017-07-01T12:00:00.000Z"
20 | //const maxDate = "2017-07-31T12:00:00.000Z"
21 |
22 | const handleChange = (v, f) => {
23 | setValue(v)
24 | setFmtValue(f)
25 |
26 | // if (ref.current) {
27 | // //console.log(ref.current)
28 | // console.log(ref.current.getValue())
29 | // console.log(ref.current.getFormattedValue())
30 | // }
31 | }
32 |
33 | return (
34 |
35 |
37 | {"Basic"}
38 |
39 |
50 |
51 | {value
52 | ? `Selected date is: ${value} (formatted: ${fmtValue})`
53 | : 'No date selected'}
54 |
55 |
56 | )
57 | }
58 |
59 | export default RDPBasic
60 |
--------------------------------------------------------------------------------
/demo/src/samples/RDPBasicDisabled.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import {
3 | FormGroup,
4 | FormText,
5 | Label
6 | } from 'reactstrap'
7 | import {DatePicker} from '../rdp'
8 |
9 | const RDPBasicDisabled = () => {
10 | const inputName = 'reactstrap_date_picker_disabled'
11 | const [value, setValue] = useState("2019-06-01T00:00:00.000Z")
12 | const [fmtValue, setFmtValue] = useState("06/01/2019")
13 |
14 | return (
15 |
16 |
18 | {"Disabled"}
19 |
20 | {setValue(v); setFmtValue(f);}}
25 | disabled = {true}
26 | />
27 |
28 | {value
29 | ? `Selected date is: ${value} (formatted: ${fmtValue})`
30 | : 'No date selected'}
31 |
32 |
33 | )
34 | }
35 |
36 | export default RDPBasicDisabled
37 |
--------------------------------------------------------------------------------
/demo/src/samples/RDPBasicFocusBlur.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import {
3 | FormGroup,
4 | FormText,
5 | Label
6 | } from 'reactstrap'
7 | import {DatePicker} from '../rdp'
8 |
9 | const RDPFocusBlur = () => {
10 | const inputName = 'reactstrap_date_picker_focus'
11 | const [value, setValue] = useState("2019-06-01T00:00:00.000Z")
12 | const [focused, setFocused] = useState(false)
13 |
14 | return (
15 |
16 |
18 | {"Focus / Blur"}
19 |
20 | setValue(v)}
25 | onBlur = {() => setFocused(false)}
26 | onFocus = {() => setFocused(true)}
27 | />
28 |
29 | {`Field is ${focused ? 'focused' : 'blurred'}`}
30 |
31 |
32 | )
33 | }
34 |
35 | export default RDPFocusBlur
36 |
--------------------------------------------------------------------------------
/demo/src/samples/RDPCustomClear.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import {
3 | FormGroup,
4 | FormText,
5 | Label
6 | } from 'reactstrap'
7 | import {DatePicker} from '../rdp'
8 |
9 | const clearButtonElement = Clear
;
10 | const RDPCustomClear = () => {
11 | const inputName = 'reactstrap_date_picker_custom_clear'
12 | const [value, setValue] = useState("2019-06-01T00:00:00.000Z")
13 |
14 | return (
15 |
16 |
18 | {"Custom Clear button"}
19 |
20 | setValue(v)}
25 | clearButtonElement = {clearButtonElement}
26 | onClear = {() => {
27 | const today= new Date()
28 | setValue(today.toISOString())
29 | }}
30 | />
31 |
32 | {`Custom text/elements can be rendered on Clear button. Current value is ${value}.`}
33 |
34 |
35 | )
36 | }
37 |
38 | export default RDPCustomClear
39 |
--------------------------------------------------------------------------------
/demo/src/samples/RDPCustomContainer.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import {
3 | FormGroup,
4 | FormText,
5 | Label
6 | } from 'reactstrap'
7 | import {DatePicker} from '../rdp'
8 |
9 | const RDPCustomContainer = () => {
10 | const inputName = 'reactstrap_date_picker_custom_form_control'
11 | const [value, setValue] = useState("2019-06-01T00:00:00.000Z")
12 | const [fmtValue, setFmtValue] = useState("06/01/2019")
13 |
14 | return (
15 |
16 |
18 | {"Custom Container"}
19 |
20 | {setValue(v); setFmtValue(f);}}
25 | calendarContainer = {document.body}
26 | />
27 |
28 | {value
29 | ? `Selected date is: ${value} (formatted: ${fmtValue})`
30 | : 'No date selected'}
31 |
32 |
33 | )
34 | }
35 |
36 | export default RDPCustomContainer
37 |
--------------------------------------------------------------------------------
/demo/src/samples/RDPCustomFormControl.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import {
3 | FormGroup,
4 | FormText,
5 | Label
6 | } from 'reactstrap'
7 | import {DatePicker} from '../rdp'
8 |
9 | const RDPCustomFormControl = () => {
10 | const inputName = 'reactstrap_date_picker_custom_form_control'
11 | const [value, setValue] = useState("2019-06-01T00:00:00.000Z")
12 | const [fmtValue, setFmtValue] = useState("06/01/2019")
13 |
14 | return (
15 |
16 |
18 | {"Custom Form Control"}
19 |
20 | {setValue(v); setFmtValue(f);}}
25 |
26 | customControl={
27 |
28 |
29 | }
30 | />
31 |
32 | {value
33 | ? `Selected date is: ${value} (formatted: ${fmtValue})`
34 | : 'No date selected'}
35 |
36 |
37 | )
38 | }
39 |
40 | export default RDPCustomFormControl
41 |
--------------------------------------------------------------------------------
/demo/src/samples/RDPCustomFormat.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import {
3 | FormGroup,
4 | FormText,
5 | Label
6 | } from 'reactstrap'
7 | import {DatePicker} from '../rdp'
8 |
9 | const spanishDayLabels = ['Dom', 'Lu', 'Ma', 'Mi', 'Ju', 'Vi', 'Sab'];
10 | const spanishMonthLabels = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'];
11 |
12 |
13 | const RDPCustomFormat = () => {
14 | const inputName = 'reactstrap_date_picker_custom_format'
15 | const [value, setValue] = useState("2019-06-01T00:00:00.000Z")
16 | return (
17 |
18 |
20 | {"Custom Format and Labels"}
21 |
22 | setValue(v)}
27 | dateFormat = {"DD/MM/YYYY"}
28 | dayLabels = {spanishDayLabels}
29 | monthLabels = {spanishMonthLabels}
30 | />
31 |
32 | {"Using ES labels and dateFormat='DD/MM/YYYY'"}
33 |
34 |
35 | )
36 | }
37 |
38 | export default RDPCustomFormat
39 |
--------------------------------------------------------------------------------
/demo/src/samples/RDPCustomInputGroup.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import {
3 | FormGroup,
4 | FormText,
5 | Label
6 | } from 'reactstrap'
7 | import {DatePicker} from '../rdp'
8 |
9 | const CustomInputGroup = ({children}) =>
10 |
11 | {children}
12 |
13 |
14 | const RDPCustomInputGroup = () => {
15 | const inputName = 'reactstrap_date_picker_custom_input_group'
16 | const [value, setValue] = useState("2019-06-01T00:00:00.000Z")
17 | const [fmtValue, setFmtValue] = useState("06/01/2019")
18 |
19 | return (
20 |
21 |
23 | {"Custom Input Group"}
24 |
25 | {setValue(v); setFmtValue(f);}}
31 | customInputGroup = { }
32 | />
33 |
34 | {value
35 | ? `Selected date is: ${value} (formatted: ${fmtValue})`
36 | : 'No date selected'}
37 |
38 |
39 | )
40 | }
41 |
42 | export default RDPCustomInputGroup
43 |
--------------------------------------------------------------------------------
/demo/src/samples/RDPCustomPickMonth.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react'
2 | import {
3 | FormGroup,
4 | FormText,
5 | Label,
6 | Input
7 | } from 'reactstrap'
8 | import {DatePicker} from '../rdp'
9 |
10 | const MONTH_NAMES= ['January', 'February', 'March', 'April',
11 | 'May', 'June', 'July', 'August', 'September',
12 | 'October', 'November', 'December']
13 |
14 | const YEARS = [2018, 2019, 2020, 2021, 2022, 2023, 2024]
15 |
16 | const PickMonthElement = ({displayDate, _minDate, _maxDate, onChangeMonth, onChangeYear}) => {
17 | const [month, setMonth]= useState((new Date(displayDate)).getMonth())
18 | const [year, setYear]= useState((new Date(displayDate)).getFullYear())
19 |
20 | useEffect(() => {
21 | setMonth((new Date(displayDate)).getMonth())
22 | setYear((new Date(displayDate)).getFullYear())
23 | }, [displayDate])
24 |
25 | const handleChangeMonth = (ev) => {
26 | const m= ev.target.value
27 | setMonth(m)
28 | onChangeMonth(m)
29 | }
30 |
31 | const handleChangeYear = (ev) => {
32 | const y= ev.target.value
33 | setYear(y)
34 | onChangeYear(y)
35 | }
36 |
37 | return (
38 |
74 | )
75 | }
76 |
77 | const RDPCustomPickMonth = () => {
78 | const inputName = 'reactstrap_date_picker_custom_pick_month'
79 | const [value, setValue] = useState("2019-06-01T00:00:00.000Z")
80 |
81 | return (
82 |
83 |
85 | {"Custom pick Month/Year selectors"}
86 |
87 | setValue(v)}
92 | pickMonthElement= {PickMonthElement}
93 | />
94 |
95 | {'Custom elements can be used as Month/Year picker'}
96 |
97 |
98 | )
99 | }
100 |
101 | export default RDPCustomPickMonth
102 |
--------------------------------------------------------------------------------
/demo/src/samples/RDPCustomPickMonthDefault.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import {
3 | FormGroup,
4 | FormText,
5 | Label
6 | } from 'reactstrap'
7 | import {DatePicker} from '../rdp'
8 |
9 | const RDPCustomPickMonthDefault = () => {
10 | const inputName = 'reactstrap_date_picker_custom_pick_month_def'
11 | const [value, setValue] = useState("2019-06-01T00:00:00.000Z")
12 |
13 | return (
14 |
15 |
17 | {"Default pick Month/Year selectors"}
18 |
19 | setValue(v)}
26 | pickMonthElement= {'default'}
27 | />
28 |
29 | {'reactstrap-date-picker provides a default Month/Year picker'}
30 |
31 |
32 | )
33 | }
34 |
35 | export default RDPCustomPickMonthDefault
36 |
--------------------------------------------------------------------------------
/demo/src/samples/RDPCustomPrevNext.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import {
3 | FormGroup,
4 | FormText,
5 | Label
6 | } from 'reactstrap'
7 | import {DatePicker} from '../rdp'
8 |
9 | const previousButtonElement = Prev
;
10 | const nextButtonElement = Next
;
11 |
12 | const RDPCustomElements = () => {
13 | const inputName = 'reactstrap_date_picker_custom_prev_next'
14 | const [value, setValue] = useState("2019-06-01T00:00:00.000Z")
15 |
16 | return (
17 |
18 |
20 | {"Custom Prev/Next buttons"}
21 |
22 | setValue(v)}
27 | nextButtonElement = {nextButtonElement}
28 | previousButtonElement= {previousButtonElement}
29 | />
30 |
31 | {'Custom text/elements can be rendered on Prev/Next calendar buttons'}
32 |
33 |
34 | )
35 | }
36 |
37 | export default RDPCustomElements
38 |
--------------------------------------------------------------------------------
/demo/src/samples/RDPCustomWeek.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import {
3 | FormGroup,
4 | FormText,
5 | Label
6 | } from 'reactstrap'
7 | import {DatePicker} from '../rdp'
8 |
9 | const RDPBasic = () => {
10 | const inputName = 'reactstrap_date_picker_cweek'
11 | const [value, setValue] = useState("2019-06-01T00:00:00.000Z")
12 |
13 | return (
14 |
15 |
17 | {"Week starts on Monday"}
18 |
19 | setValue(v)}
24 | weekStartsOn = {1}
25 | />
26 |
27 | {"Week starts on Monday, weekStartsOn=1"}
28 |
29 |
30 | )
31 | }
32 |
33 | export default RDPBasic
34 |
--------------------------------------------------------------------------------
/demo/src/samples/RDPPlacementBottom.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import {
3 | FormGroup,
4 | FormText,
5 | Label
6 | } from 'reactstrap'
7 | import {DatePicker} from '../rdp'
8 |
9 | const RDPPlacementBottom = () => {
10 | const inputName = 'reactstrap_date_picker_placement_bottom'
11 | const [value, setValue] = useState("2019-06-01T00:00:00.000Z")
12 |
13 | return (
14 |
15 |
17 | {"Bottom"}
18 |
19 | setValue(v)}
24 | calendarPlacement = "bottom"
25 | />
26 |
27 | {"calendarPlacement='bottom'"}
28 |
29 |
30 | )
31 | }
32 |
33 | export default RDPPlacementBottom
34 |
--------------------------------------------------------------------------------
/demo/src/samples/RDPPlacementLeft.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import {
3 | FormGroup,
4 | FormText,
5 | Label
6 | } from 'reactstrap'
7 | import {DatePicker} from '../rdp'
8 |
9 | const RDPPlacementLeft = () => {
10 | const inputName = 'reactstrap_date_picker_placement_left'
11 | const [value, setValue] = useState("2019-06-01T00:00:00.000Z")
12 |
13 | return (
14 |
15 |
17 | {"Left"}
18 |
19 | setValue(v)}
24 | calendarPlacement = "left"
25 | />
26 |
27 | {"calendarPlacement='left'"}
28 |
29 |
30 | )
31 | }
32 |
33 | export default RDPPlacementLeft
34 |
--------------------------------------------------------------------------------
/demo/src/samples/RDPPlacementRight.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import {
3 | FormGroup,
4 | FormText,
5 | Label
6 | } from 'reactstrap'
7 | import {DatePicker} from '../rdp'
8 |
9 | const RDPPlacementRight = () => {
10 | const inputName = 'reactstrap_date_picker_placement_right'
11 | const [value, setValue] = useState("2019-06-01T00:00:00.000Z")
12 |
13 | return (
14 |
15 |
17 | {"Right"}
18 |
19 | setValue(v)}
24 | calendarPlacement = "right"
25 | />
26 |
27 | {"calendarPlacement='right'"}
28 |
29 |
30 | )
31 | }
32 |
33 | export default RDPPlacementRight
34 |
--------------------------------------------------------------------------------
/demo/src/samples/RDPPlacementTop.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import {
3 | FormGroup,
4 | FormText,
5 | Label
6 | } from 'reactstrap'
7 | import {DatePicker} from '../rdp'
8 |
9 | const RDPPlacementTop = () => {
10 | const inputName = 'reactstrap_date_picker_placement_top'
11 | const [value, setValue] = useState("2019-06-01T00:00:00.000Z")
12 |
13 | return (
14 |
15 |
17 | {"Top"}
18 |
19 | setValue(v)}
24 | calendarPlacement = "top"
25 | />
26 |
27 | {"calendarPlacement='top'"}
28 |
29 |
30 | )
31 | }
32 |
33 | export default RDPPlacementTop
34 |
--------------------------------------------------------------------------------
/demo/src/samples/RDPSizeLarge.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import {
3 | FormGroup,
4 | FormText,
5 | Label
6 | } from 'reactstrap'
7 | import {DatePicker} from '../rdp'
8 |
9 | const RDPSizeLarge = () => {
10 | const inputName = 'reactstrap_date_picker_size-large'
11 | const [value, setValue] = useState("2019-06-01T00:00:00.000Z")
12 |
13 | return (
14 |
15 |
17 | {"Large"}
18 |
19 | setValue(v)}
24 | size = "lg"
25 | />
26 |
27 | {"Large size input, size='lg'"}
28 |
29 |
30 | )
31 | }
32 |
33 | export default RDPSizeLarge
34 |
--------------------------------------------------------------------------------
/demo/src/samples/RDPSizeSmall.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import {
3 | FormGroup,
4 | FormText,
5 | Label
6 | } from 'reactstrap'
7 | import {DatePicker} from '../rdp'
8 |
9 | const RDPSizeSmall = () => {
10 | const inputName = 'reactstrap_date_picker_size-small'
11 | const [value, setValue] = useState("2019-06-01T00:00:00.000Z")
12 |
13 | return (
14 |
15 |
17 | {"Small"}
18 |
19 | setValue(v)}
24 | size = "sm"
25 | />
26 |
27 | {"Small size input, size='sm'"}
28 |
29 |
30 | )
31 | }
32 |
33 | export default RDPSizeSmall
34 |
--------------------------------------------------------------------------------
/demo/src/samples/RDPValidityInvalid.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import {
3 | FormGroup,
4 | FormText,
5 | Label
6 | } from 'reactstrap'
7 | import {DatePicker} from '../rdp'
8 |
9 | const RDPValidityInvalid = () => {
10 | const inputName = 'reactstrap_date_picker_valid'
11 | const [value, setValue] = useState("2019-06-01T00:00:00.000Z")
12 | const [fmtValue, setFmtValue] = useState("06/01/2019")
13 |
14 | return (
15 |
16 |
18 | {"Invalid"}
19 |
20 | {setValue(v); setFmtValue(f);}}
25 | invalid = {true}
26 | />
27 |
28 | {value
29 | ? `Selected date is: ${value} (formatted: ${fmtValue})`
30 | : 'No date selected'}
31 |
32 |
33 | )
34 | }
35 |
36 | export default RDPValidityInvalid
37 |
--------------------------------------------------------------------------------
/demo/src/samples/RDPValidityValid.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import {
3 | FormGroup,
4 | FormText,
5 | Label
6 | } from 'reactstrap'
7 | import {DatePicker} from '../rdp'
8 |
9 | const RDPValidityValid = () => {
10 | const inputName = 'reactstrap_date_picker_valid'
11 | const [value, setValue] = useState("2019-06-01T00:00:00.000Z")
12 | const [fmtValue, setFmtValue] = useState("06/01/2019")
13 |
14 | return (
15 |
16 |
18 | {"Valid"}
19 |
20 | {setValue(v); setFmtValue(f);}}
25 | valid = {true}
26 | />
27 |
28 | {value
29 | ? `Selected date is: ${value} (formatted: ${fmtValue})`
30 | : 'No date selected'}
31 |
32 |
33 | )
34 | }
35 |
36 | export default RDPValidityValid
37 |
--------------------------------------------------------------------------------
/logo/favicon/reactstrap-date-picker.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/afialapis/reactstrap-date-picker/8be567d29eee1dfe43c80524e7463b6ca9ea721f/logo/favicon/reactstrap-date-picker.ico
--------------------------------------------------------------------------------
/logo/reactstrap-date-picker.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/afialapis/reactstrap-date-picker/8be567d29eee1dfe43c80524e7463b6ca9ea721f/logo/reactstrap-date-picker.png
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "reactstrap-date-picker",
3 | "version": "2.0.0-beta.4",
4 | "description": "Reactstrap based, zero dependencies, date picker",
5 | "author": "Donato Lorenzo ",
6 | "contributors": [
7 | "Donato Lorenzo "
8 | ],
9 | "license": "MIT",
10 | "repository": {
11 | "type": "git",
12 | "url": "https://github.com/afialapis/reactstrap-date-picker.git"
13 | },
14 | "bugs": {
15 | "url": "https://github.com/afialapis/reactstrap-date-picker/issues"
16 | },
17 | "homepage": "https://reactstrap-date-picker.afialapis.com/",
18 | "files": [
19 | "lib",
20 | "dist"
21 | ],
22 | "type": "module",
23 | "main": "./lib/index.cjs",
24 | "cjs": "./dist/reactstrap-date-picker.cjs",
25 | "browser": "./dist/reactstrap-date-picker.umd.js",
26 | "module": "./dist/reactstrap-date-picker.mjs",
27 | "exports": {
28 | "import": "./dist/reactstrap-date-picker.mjs",
29 | "default": "./lib/index.cjs",
30 | "require": "./dist/reactstrap-date-picker.cjs"
31 | },
32 | "scripts": {
33 | "postinstall": "patch-package",
34 | "clean-demo": "rm -rf demo/dist && mkdir -p demo/dist/img && ln -s ./logo/favicon/reactstrap-date-picker.ico demo/dist/img/",
35 | "clean-lib": "rm -rf lib && mkdir lib",
36 | "clean-dist": "rm -rf dist && mkdir dist",
37 | "clean-site": "rm -rf arredemo",
38 | "clean-all": "npm run --silent clean-demo && npm run --silent clean-lib && npm run --silent clean-dist && npm run --silent clean-site",
39 | "lint": "npx xeira lint",
40 | "test": "npx xeira test --files=./test/before.mjs,./test/units/integrity/*.cjs,./test/units/properties/**/*.cjs",
41 | "lib": "npm run --silent clean-lib && npx xeira transpile",
42 | "dist": "npm run --silent clean-dist && npx xeira bundle",
43 | "site": "npm run --silent clean-site && npx xeira site",
44 | "prepare": "npm run --silent clean-demo && npm run --silent lint && npm run --silent test && npm run --silent lib && npm run --silent dist && npm run --silent site",
45 | "demo": "npm run --silent clean-demo && npx xeira demo --port=8003",
46 | "reset": "npm run --silent clean-all && rm -fr node_modules package-lock.json && npm i"
47 | },
48 | "keywords": [
49 | "js",
50 | "react",
51 | "reactstrap",
52 | "date",
53 | "picker"
54 | ],
55 | "devDependencies": {
56 | "xeira": "^1.0.1",
57 | "bootstrap": "^5.1.0",
58 | "react": "^18.3.1",
59 | "react-dom": "^18.3.1",
60 | "reactstrap": "^9.2.3"
61 | },
62 | "peerDependencies": {
63 | "bootstrap": "^5.1.0",
64 | "react": "^18.3.1",
65 | "react-dom": "^18.3.1",
66 | "reactstrap": "^9.2.3"
67 | },
68 | "overrides": {
69 | "css-select": {
70 | "nth-check": "2.0.1"
71 | }
72 | },
73 | "eslintConfig": {
74 | "extends": [
75 | "./node_modules/xeira/configs/eslint.react.cjs"
76 | ]
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/patches/react-transition-group+4.4.5.patch:
--------------------------------------------------------------------------------
1 | diff --git a/node_modules/react-transition-group/cjs/Transition.js b/node_modules/react-transition-group/cjs/Transition.js
2 | index b44cb76..c18d466 100644
3 | --- a/node_modules/react-transition-group/cjs/Transition.js
4 | +++ b/node_modules/react-transition-group/cjs/Transition.js
5 | @@ -540,7 +540,9 @@ Transition.propTypes = process.env.NODE_ENV !== "production" ? {
6 | */
7 | timeout: function timeout(props) {
8 | var pt = _PropTypes.timeoutsShape;
9 | - if (!props.addEndListener) pt = pt.isRequired;
10 | + // reactstrap-date-picker patch
11 | + // for removing warnings about null prop
12 | + //if (!props.addEndListener) pt = pt.isRequired;
13 |
14 | for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
15 | args[_key - 1] = arguments[_key];
16 | diff --git a/node_modules/react-transition-group/esm/Transition.js b/node_modules/react-transition-group/esm/Transition.js
17 | index 986d29f..d8d037b 100644
18 | --- a/node_modules/react-transition-group/esm/Transition.js
19 | +++ b/node_modules/react-transition-group/esm/Transition.js
20 | @@ -518,7 +518,10 @@ Transition.propTypes = process.env.NODE_ENV !== "production" ? {
21 | */
22 | timeout: function timeout(props) {
23 | var pt = timeoutsShape;
24 | - if (!props.addEndListener) pt = pt.isRequired;
25 | +
26 | + // reactstrap-date-picker patch
27 | + // for removing warnings about null prop
28 | + //if (!props.addEndListener) pt = pt.isRequired;
29 |
30 | for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
31 | args[_key - 1] = arguments[_key];
32 |
--------------------------------------------------------------------------------
/patches/reactstrap+9.2.3.patch:
--------------------------------------------------------------------------------
1 | diff --git a/node_modules/reactstrap/esm/Popover.js b/node_modules/reactstrap/esm/Popover.js
2 | index 18f0fc4..5b38720 100644
3 | --- a/node_modules/reactstrap/esm/Popover.js
4 | +++ b/node_modules/reactstrap/esm/Popover.js
5 | @@ -2,22 +2,28 @@ function _extends() { _extends = Object.assign ? Object.assign.bind() : function
6 | import React from 'react';
7 | import classNames from 'classnames';
8 | import TooltipPopoverWrapper, { propTypes } from './TooltipPopoverWrapper';
9 | +
10 | +// reactstrap-date-picker patch
11 | +// for removing warnings about defaultProps
12 | +const _DEFAULT_OFFSET = [0, 8];
13 | +
14 | var defaultProps = {
15 | placement: 'right',
16 | placementPrefix: 'bs-popover',
17 | trigger: 'click',
18 | - offset: [0, 8]
19 | + offset: _DEFAULT_OFFSET
20 | };
21 | function Popover(props) {
22 | var arrowClasses = classNames('popover-arrow', props.arrowClassName);
23 | var popperClasses = classNames('popover', 'show', props.popperClassName);
24 | var classes = classNames('popover-inner', props.innerClassName);
25 | - return /*#__PURE__*/React.createElement(TooltipPopoverWrapper, _extends({}, props, {
26 | + return /*#__PURE__*/React.createElement(TooltipPopoverWrapper, _extends({}, defaultProps, props, {
27 | arrowClassName: arrowClasses,
28 | popperClassName: popperClasses,
29 | innerClassName: classes
30 | }));
31 | }
32 | Popover.propTypes = propTypes;
33 | -Popover.defaultProps = defaultProps;
34 | +//Popover.defaultProps = defaultProps;
35 | +
36 | export default Popover;
37 | \ No newline at end of file
38 | diff --git a/node_modules/reactstrap/lib/Popover.js b/node_modules/reactstrap/lib/Popover.js
39 | index 318f966..20265e7 100644
40 | --- a/node_modules/reactstrap/lib/Popover.js
41 | +++ b/node_modules/reactstrap/lib/Popover.js
42 | @@ -11,23 +11,28 @@ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "functio
43 | function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
44 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
45 | function _extends() { _extends = Object.assign ? Object.assign.bind() : 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); }
46 | +
47 | +// reactstrap-date-picker patch
48 | +// for removing warnings about defaultProps
49 | +const _DEFAULT_OFFSET = [0, 8];
50 | +
51 | const defaultProps = {
52 | placement: 'right',
53 | placementPrefix: 'bs-popover',
54 | trigger: 'click',
55 | - offset: [0, 8]
56 | + offset: _DEFAULT_OFFSET
57 | };
58 | function Popover(props) {
59 | const arrowClasses = (0, _classnames.default)('popover-arrow', props.arrowClassName);
60 | const popperClasses = (0, _classnames.default)('popover', 'show', props.popperClassName);
61 | const classes = (0, _classnames.default)('popover-inner', props.innerClassName);
62 | - return /*#__PURE__*/_react.default.createElement(_TooltipPopoverWrapper.default, _extends({}, props, {
63 | + return /*#__PURE__*/_react.default.createElement(_TooltipPopoverWrapper.default, _extends({}, defaultProps, props, {
64 | arrowClassName: arrowClasses,
65 | popperClassName: popperClasses,
66 | innerClassName: classes
67 | }));
68 | }
69 | Popover.propTypes = _TooltipPopoverWrapper.propTypes;
70 | -Popover.defaultProps = defaultProps;
71 | +//Popover.defaultProps = defaultProps;
72 | var _default = Popover;
73 | exports.default = _default;
74 | \ No newline at end of file
75 |
--------------------------------------------------------------------------------
/playground/check/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 | reactstrap-date-picker playground (current)
10 |
11 |
12 |
15 |
16 |
17 |
18 |
19 |
28 |
29 |
30 |
33 |
34 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/playground/current/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 | reactstrap-date-picker playground (current)
10 |
11 |
12 |
13 |
14 |
15 |
24 |
25 |
26 |
29 |
30 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/playground/future/future_build.sh:
--------------------------------------------------------------------------------
1 | rm -fr dist
2 | mkdir dist
3 | cd ../..
4 | npm run clean-all
5 | mv package.json package.json.current
6 | cp playground/future/package.json .
7 | npm i
8 | cp ./dist/*umd* ./playground/future/dist
9 |
10 | mv package.json.current package.json
11 | npm run reset
--------------------------------------------------------------------------------
/playground/future/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 | reactstrap-date-picker playground (future)
10 |
11 |
12 |
13 |
14 |
15 |
24 |
25 |
26 |
29 |
30 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/playground/future/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "reactstrap-date-picker",
3 | "version": "0.0.16",
4 | "description": "Reactstrap based, zero dependencies, date picker",
5 | "author": "Donato Lorenzo ",
6 | "contributors": [
7 | "Donato Lorenzo "
8 | ],
9 | "license": "MIT",
10 | "repository": {
11 | "type": "git",
12 | "url": "https://github.com/afialapis/reactstrap-date-picker.git"
13 | },
14 | "bugs": {
15 | "url": "https://github.com/afialapis/reactstrap-date-picker/issues"
16 | },
17 | "homepage": "https://reactstrap-date-picker.afialapis.com/",
18 | "files": [
19 | "lib",
20 | "dist"
21 | ],
22 | "main": "lib/index.js",
23 | "cjs": "dist/reactstrap-date-picker.cjs.js",
24 | "browser": "dist/reactstrap-date-picker.umd.js",
25 | "module": "dist/reactstrap-date-picker.es.js",
26 | "scripts": {
27 | "lint": "eslint src",
28 | "clean-lib": "rm -rf lib && mkdir lib",
29 | "clean-dist": "rm -rf dist && mkdir dist",
30 | "test_command": "mocha --exit --timeout 500 --slow 300 --require @babel/register --require ./test/dom.js --require ignore-styles ./test/helpers.js ",
31 | "test_file": "npm run test_command --bail ",
32 | "test_r17": "npm run test_command --paralell $(find ./test -name '*.js' ! -path '**/_*.js')",
33 | "test": "npm run test_command --bail $(find ./test -name '*.js' ! -path '**/_*.js')",
34 | "lib": "npm run clean-lib && babel src -d lib",
35 | "dist": "npm run clean-dist && rollup -c",
36 | "prepare": "npm run lint && npm run test && npm run lib && npm run dist",
37 | "demo": "rm -rf demo/dist && mkdir demo/dist && rollup -c rollup.demo.js -w",
38 | "reset": "rm -rf demo/dist && npm run clean-lib && npm run clean-dist && rm -fr node_modules package-lock.json && npm i"
39 | },
40 | "keywords": [
41 | "js",
42 | "react",
43 | "reactstrap",
44 | "date",
45 | "picker"
46 | ],
47 | "devDependencies": {
48 | "@babel/cli": "^7.17.10",
49 | "@babel/core": "^7.18.2",
50 | "@babel/eslint-parser": "^7.18.2",
51 | "@babel/preset-env": "^7.18.2",
52 | "@babel/preset-react": "^7.17.12",
53 | "@babel/register": "^7.17.7",
54 | "@rollup/plugin-babel": "^5.3.1",
55 | "@rollup/plugin-commonjs": "^22.0.0",
56 | "@rollup/plugin-node-resolve": "^13.3.0",
57 | "@rollup/plugin-replace": "^4.0.0",
58 | "bootstrap": "^5.1.3",
59 | "chai": "^4.3.6",
60 | "enzyme": "^3.11.0",
61 | "enzyme-adapter-react-16": "^1.15.6",
62 | "eslint": "^8.17.0",
63 | "eslint-plugin-react": "^7.30.0",
64 | "eslint-plugin-react-hooks": "^4.5.0",
65 | "ignore-styles": "^5.0.1",
66 | "jsdom": "^19.0.0",
67 | "mocha": "^10.0.0",
68 | "node-sass": "^7.0.1",
69 | "node-uuid": "^1.4.8",
70 | "postcss": "^8.4.14",
71 | "react": "^16.13.1",
72 | "react-dom": "^16.13.1",
73 | "reactstrap": "9.0.1",
74 | "rollup": "^2.75.6",
75 | "rollup-plugin-livereload": "^2.0.5",
76 | "rollup-plugin-postcss": "^4.0.2",
77 | "rollup-plugin-serve": "^1.1.0",
78 | "rollup-plugin-terser": "^7.0.2"
79 | },
80 | "peerDependencies": {
81 | "react": ">=16.13.1",
82 | "react-dom": ">=16.13.1",
83 | "reactstrap": ">=9.0.1"
84 | },
85 | "overrides": {
86 | "enzyme": {
87 | "cheerio": "1.0.0-rc.3"
88 | }
89 | }
90 | }
91 |
92 |
--------------------------------------------------------------------------------
/playground/gh_issue.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | reactstrap 9
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/src/DatePicker.mjs:
--------------------------------------------------------------------------------
1 | import React, { useImperativeHandle, forwardRef } from 'react'
2 |
3 | import { useCheckProps } from './util/useCheckProps'
4 | import { InputGroup } from './input/InputGroup'
5 | import { InputOverlay } from './input/InputOverlay'
6 | import { InputHidden } from './input/InputHidden'
7 | import { InputClearButton } from './input/InputClearButton'
8 | import { InputControlInput } from './input/InputControlInput'
9 | import { useInputValues } from './input/useInputValues'
10 | import { useInputIds } from './input/useInputIds'
11 | import { useFixedDayLabels } from './input/useDayLabels'
12 | import { Calendar } from './calendar/Calendar'
13 | import { useCalendarProps } from './calendar/useCalendarProps'
14 |
15 | const _defaultDateFormat= () => {
16 | const language = typeof window !== 'undefined' && window.navigator ? (window.navigator.userLanguage || window.navigator.language || '').toLowerCase() : ''
17 | const dateFormat = !language || language === 'en-us' ? 'MM/DD/YYYY' : 'DD/MM/YYYY'
18 | return dateFormat
19 | }
20 |
21 | const DEFAULT_DAY_LABELS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
22 | const DEFAULT_MONTH_LABELS = ['January', 'February', 'March', 'April',
23 | 'May', 'June', 'July', 'August', 'September',
24 | 'October', 'November', 'December']
25 |
26 | const DatePickerBase = (props, ref) => {
27 |
28 | const {
29 | // Global props
30 | value,
31 | defaultValue,
32 | id,
33 | name,
34 | dateFormat = _defaultDateFormat(),
35 | minDate,
36 | maxDate,
37 | clearButtonElement = '×',
38 | showClearButton = true,
39 |
40 | // Event props
41 | onInvalid,
42 | onChange,
43 | onClear,
44 | onBlur,
45 | onFocus,
46 |
47 | // Input Group props
48 | size,
49 | valid,
50 | invalid,
51 | customInputGroup,
52 |
53 | // Input props
54 | autoComplete = 'on',
55 | autoFocus = false,
56 | disabled = false,
57 | noValidate = false,
58 | placeholder,
59 | required,
60 | className,
61 | style = undefined /* {
62 | width: '100%'
63 | } */,
64 | inputRef,
65 | customControl,
66 | children,
67 |
68 | // Calendar props
69 | // target,
70 | calendarContainer,
71 |
72 | dayLabels = DEFAULT_DAY_LABELS,
73 | monthLabels = DEFAULT_MONTH_LABELS,
74 | weekStartsOn,
75 | showWeeks = false,
76 | previousButtonElement= '<',
77 | nextButtonElement = '>',
78 | pickMonthElement = undefined,
79 | showTodayButton = false,
80 | todayButtonLabel = 'Today',
81 | roundedCorners = false,
82 | cellPadding = '5px',
83 | calendarPlacement = 'bottom'
84 | } = props
85 |
86 | const propError= useCheckProps(value, defaultValue)
87 | if (propError!=undefined) {
88 | throw new Error(propError)
89 | }
90 |
91 |
92 | const [hiddenInputRef, overlayContainerRef, popoverRef, controlInputRef, open, placement,
93 | handleFocus, handleBlur] = useCalendarProps(calendarPlacement, inputRef, autoFocus, onBlur, onFocus)
94 |
95 | const [innerValue, inputValue, displayDate,
96 | selectedDate, handleClear, handleInputChange,
97 | handleChangeMonth, handleChangeDate, handleBadInputOnBlur] = useInputValues(controlInputRef, value, defaultValue,
98 | minDate, maxDate, dateFormat, onClear, onChange)
99 |
100 | const [groupInputId, hiddenInputId, controlInputId, overlayId] = useInputIds(id, name, customControl)
101 |
102 | useImperativeHandle(ref, () => ({
103 | getValue: () => {
104 | return selectedDate ? selectedDate.toISOString() : null;
105 | },
106 | getFormattedValue: () => {
107 | return displayDate ? inputValue : null;
108 | },
109 | getNode: () => controlInputRef?.current
110 | })) //, [controlInputRef, displayDate, inputValue, selectedDate]))
111 |
112 |
113 | const fixedDayLabels = useFixedDayLabels(dayLabels, weekStartsOn)
114 |
115 | const handleChangeDateAndBlur = (nSelectedDate) => {
116 | handleChangeDate(nSelectedDate)
117 | handleBlur(true)
118 | }
119 |
120 | return (
121 |
125 |
126 | handleFocus()}
143 | onBlur = {(event) => {handleBadInputOnBlur(); handleBlur(event) }}
144 | onChange = {() => handleInputChange()}
145 | />
146 |
147 |
150 |
151 | {overlayContainerRef.current == undefined
152 | ? null
153 | :
154 |
155 | handleChangeMonth(newDisplayDate)}
168 | monthLabels = {monthLabels}
169 | cellPadding = {cellPadding}
170 | selectedDate = {selectedDate}
171 | onChange = {(newSelectedDate) => handleChangeDateAndBlur(newSelectedDate)}
172 | dayLabels = {fixedDayLabels}
173 | weekStartsOn = {weekStartsOn}
174 | showTodayButton = {showTodayButton}
175 | todayButtonLabel = {todayButtonLabel}
176 | roundedCorners = {roundedCorners}
177 | showWeeks = {showWeeks}/>
178 | }
179 |
180 |
181 |
188 |
189 |
190 | {(showClearButton && !customControl)
191 | ?
192 | handleClear()}
197 | />
198 | : null
199 | }
200 |
201 | {children}
202 |
203 |
204 | )
205 | }
206 |
207 | const DatePicker = forwardRef(DatePickerBase)
208 |
209 | export {DatePicker}
210 |
--------------------------------------------------------------------------------
/src/calendar/Calendar.mjs:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Popover, PopoverHeader, PopoverBody} from 'reactstrap'
3 | import {setTimeToNoon} from '../util/setTimeToNoon'
4 | import {CalendarHeader} from './CalendarHeader'
5 | import {CalendarSubHeader} from './CalendarSubHeader'
6 | import {CalendarBody} from './CalendarBody'
7 | import {CalendarFooter} from './CalendarFooter'
8 | import {useCalendarDays} from './useCalendarDays'
9 |
10 | const Calendar = (
11 | {popoverRef, selectedDate, displayDate, minDate, maxDate, onChange, dayLabels,
12 | cellPadding, weekStartsOn, showTodayButton, todayButtonLabel,
13 | roundedCorners, showWeeks, monthLabels, previousButtonElement,
14 | nextButtonElement, pickMonthElement, placement, open,
15 | container, target, onChangeMonth}) => {
16 | const calendarDays = useCalendarDays(displayDate, selectedDate, minDate, maxDate, weekStartsOn)
17 |
18 | const handleDayClick = (e) => {
19 | const day = e.currentTarget.getAttribute('data-day')
20 | const newSelectedDate = setTimeToNoon(new Date(displayDate))
21 | newSelectedDate.setDate(day)
22 | onChange(newSelectedDate)
23 | }
24 |
25 | const handleTodayClick = () => {
26 | const newSelectedDate = setTimeToNoon(new Date())
27 | onChange(newSelectedDate)
28 | }
29 |
30 | return (
31 | <>
32 |
33 | handleHide()}
37 | isOpen = {open}
38 | container = {container}
39 | target = {target}
40 | placement = {placement}
41 | // delay = {200} // does not apply for us (manual triggering)
42 | >
43 |
44 | onChangeMonth(newDisplayDate)}
52 | monthLabels = {monthLabels}/>
53 |
54 |
55 |
56 |
57 |
62 |
63 |
70 |
71 |
78 |
79 |
80 |
81 | >
82 | )
83 | }
84 |
85 | export { Calendar }
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/src/calendar/CalendarBody.mjs:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {CalendarDayOutOfMonth} from './CalendarDayOutOfMonth'
3 | import {CalendarDayInMonth} from './CalendarDayInMonth'
4 | import {CalendarWeekNum} from './CalendarWeekNum'
5 |
6 | const CalendarBody = ({calendarDays, showWeeks, onDayClick, cellPadding, roundedCorners}) => {
7 | if (! calendarDays) {
8 | return
9 | }
10 |
11 | return (
12 |
13 | {calendarDays.map( (week, weekIndex) =>
14 |
15 | {showWeeks
16 | ?
20 | : null
21 | }
22 | {week.weekDays.map((weekDay, weekDayIndex) =>
23 | weekDay.inMonth
24 | ?
32 | :
34 | )}
35 |
36 | )}
37 |
38 | )
39 | }
40 |
41 | export {CalendarBody}
42 |
--------------------------------------------------------------------------------
/src/calendar/CalendarDayInMonth.mjs:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const CAL_DAY_CLASSNAME_BY_MODE= {
4 | 'normal': '',
5 | 'muted': 'text-muted',
6 | 'selected': 'bg-primary',
7 | 'current': 'text-primary'
8 | }
9 |
10 | const CalendarDayInMonth = ({day, mode, onDayClick, cellPadding, roundedCorners}) => {
11 |
12 | const handleClick = (ev) => {
13 | if (mode!='muted') {
14 | onDayClick(ev)
15 | }
16 | }
17 |
18 | return (
19 |
26 | {day}
27 |
28 |
29 | )
30 | }
31 |
32 | export {CalendarDayInMonth}
33 |
34 |
--------------------------------------------------------------------------------
/src/calendar/CalendarDayOutOfMonth.mjs:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const CalendarDayOutOfMonth = () =>
4 |
5 |
6 | export {CalendarDayOutOfMonth}
--------------------------------------------------------------------------------
/src/calendar/CalendarFooter.mjs:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Button} from 'reactstrap'
3 |
4 | const CalendarFooter = ({dayLabels, showWeeks, handleTodayClick, showTodayButton, todayButtonLabel}) => {
5 | if (!showTodayButton) {
6 | return null
7 | }
8 |
9 | return (
10 |
11 |
12 |
13 | handleTodayClick()}>
18 | {todayButtonLabel}
19 |
20 |
21 |
22 |
23 | )
24 |
25 | }
26 |
27 | export {CalendarFooter}
--------------------------------------------------------------------------------
/src/calendar/CalendarHeader.mjs:
--------------------------------------------------------------------------------
1 |
2 | import React, {useState, useEffect} from 'react'
3 | import {compareMonths} from '../util/compareMonths'
4 | import PickMonthDefault from './pickmonth/PickMonthDefault'
5 |
6 | function CalendarHeader ({
7 | previousButtonElement, nextButtonElement, pickMonthElement,
8 | displayDate, minDate, maxDate, onChange, monthLabels}) {
9 |
10 | const [displayingMinMonth, setDisplayingMinMonth]= useState(false)
11 | const [displayingMaxMonth, setDisplayingMaxMonth]= useState(false)
12 | const [title, setTitle]= useState('')
13 | const PickMonthElement = pickMonthElement
14 |
15 | useEffect(() => {
16 | if (displayDate==undefined) {
17 | return
18 | }
19 |
20 | if (!minDate) {
21 | setDisplayingMinMonth(false)
22 | } else {
23 | setDisplayingMinMonth(compareMonths(displayDate, minDate))
24 | }
25 |
26 | if (!maxDate) {
27 | setDisplayingMaxMonth(false)
28 | } else {
29 | setDisplayingMaxMonth(compareMonths(displayDate, maxDate))
30 | }
31 |
32 | try {
33 | if (monthLabels) {
34 | setTitle(`${monthLabels[displayDate.getMonth()]} ${displayDate.getFullYear()}`)
35 | }
36 | } catch(e) {
37 | console.error(e)
38 | }
39 |
40 | }, [displayDate, minDate, maxDate, monthLabels])
41 |
42 |
43 | const handleChangeMonthIncr = (inc) => {
44 | const newDisplayDate = new Date(displayDate)
45 | newDisplayDate.setMonth(newDisplayDate.getMonth() + inc, 1)
46 | onChange(newDisplayDate)
47 | }
48 |
49 | const handleChangeMonth = (m) => {
50 | const newDisplayDate = new Date(displayDate)
51 | newDisplayDate.setMonth(m)
52 | onChange(newDisplayDate)
53 | }
54 |
55 | const handleChangeYear = (y) => {
56 | const newDisplayDate = new Date(displayDate)
57 | newDisplayDate.setFullYear(y)
58 | onChange(newDisplayDate)
59 | }
60 |
61 | return (
62 |
63 |
handleChangeMonthIncr(-1)}
65 | style = {{cursor: 'pointer', userSelect: 'none', flexBasis: '1.25em', alignSelf: 'center'}}>
66 | {displayingMinMonth ? null : previousButtonElement}
67 |
68 |
69 |
{
71 | (PickMonthElement==null || PickMonthElement==='none')
72 | ?
{title}
73 | : PickMonthElement==='default'
74 | ?
handleChangeMonth(m) }
80 | onChangeYear = { (y) => handleChangeYear(y) }/>
81 | : handleChangeMonth(m) }
86 | onChangeYear = { (y) => handleChangeYear(y) }/>
87 |
88 | }
89 |
handleChangeMonthIncr(+1)}
91 | style = {{cursor: 'pointer', userSelect: 'none', flexBasis: '1.25em', alignSelf: 'center'}}>
92 | {displayingMaxMonth ? null : nextButtonElement}
93 |
94 |
95 | )
96 |
97 | }
98 |
99 | export {CalendarHeader}
100 |
--------------------------------------------------------------------------------
/src/calendar/CalendarSubHeader.mjs:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const CalendarSubHeader = ({dayLabels, showWeeks, cellPadding}) =>
4 |
5 |
6 |
7 | {showWeeks
8 | ?
10 | : null
11 | }
12 | {dayLabels.map((label, index) =>
13 |
16 | {label}
17 |
18 | )}
19 |
20 |
21 |
22 | export {CalendarSubHeader}
--------------------------------------------------------------------------------
/src/calendar/CalendarWeekNum.mjs:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const CalendarWeekNum = ({weekNum, cellPadding}) =>
4 |
6 | {weekNum}
7 |
8 |
9 | export {CalendarWeekNum}
10 |
--------------------------------------------------------------------------------
/src/calendar/pickmonth/PickMonthDefault.mjs:
--------------------------------------------------------------------------------
1 | import React, {useState, useEffect} from 'react'
2 | import {Input} from 'reactstrap'
3 |
4 | const _getYearList = (minDate, maxDate) => {
5 | const minYear= minDate
6 | ? (new Date(minDate)).getFullYear()
7 | : 1970
8 | const maxYear= maxDate
9 | ? (new Date(maxDate)).getFullYear()
10 | : 2045
11 | let yList= []
12 | for (let y=minYear; y<=maxYear; y++) {
13 | yList.push(y)
14 | }
15 | return yList
16 | }
17 |
18 |
19 | const PickMonthDefault = ({displayDate, minDate, maxDate, monthLabels, onChangeMonth, onChangeYear}) => {
20 | const [month, setMonth]= useState((new Date(displayDate)).getMonth())
21 | const [year, setYear]= useState((new Date(displayDate)).getFullYear())
22 | const [yearList, setYearList] = useState(_getYearList(minDate, maxDate))
23 |
24 | useEffect(() => {
25 | setMonth((new Date(displayDate)).getMonth())
26 | setYear((new Date(displayDate)).getFullYear())
27 | }, [displayDate])
28 |
29 | useEffect(() => {
30 | setYearList(_getYearList(minDate, maxDate))
31 | }, [minDate, maxDate])
32 |
33 | const handleChangeMonth = (ev) => {
34 | const m= ev.target.value
35 | setMonth(m)
36 | onChangeMonth(m)
37 | }
38 |
39 | const handleChangeYear = (ev) => {
40 | const y= ev.target.value
41 | setYear(y)
42 | onChangeYear(y)
43 | }
44 |
45 |
46 | return (
47 |
90 | )
91 | }
92 |
93 | export default PickMonthDefault
94 |
--------------------------------------------------------------------------------
/src/calendar/useCalendarDays.mjs:
--------------------------------------------------------------------------------
1 | import {useState, useEffect} from 'react'
2 | import {setTimeToNoon} from '../util/setTimeToNoon'
3 |
4 | const DAYS_BY_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
5 |
6 | /**
7 | groupByWeeks: {
8 | year,
9 | month,
10 | weeks: [
11 | {weekNum: N,
12 | wekDays: [
13 | {inMonth: true, day: N, mode: ''}
14 | or
15 | {inMonth: false}
16 | ]
17 | },...
18 | ]
19 | }
20 | */
21 |
22 | function _groupByWeeks(year, month, weekStartsOn) {
23 | if (year == undefined || month == undefined) {
24 | return undefined
25 | }
26 |
27 | const firstDay = new Date(year, month, 1)
28 | const startingDay = weekStartsOn > 1
29 | ? firstDay.getDay() - weekStartsOn + 7
30 | : weekStartsOn === 1
31 | ? (firstDay.getDay() === 0 ? 6 : firstDay.getDay() - 1)
32 | : firstDay.getDay();
33 |
34 | let monthLength = DAYS_BY_MONTH[month]
35 | if (month == 1) {
36 | if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
37 | monthLength = 29;
38 | }
39 | }
40 |
41 | const isInMonth = (monthDay, weekIndex, weekDay) => {
42 | if (monthDay <= monthLength && (weekIndex > 0 || weekDay >= startingDay)) {
43 | return true
44 | }
45 | return false
46 | }
47 |
48 | const getWeekNumber = (monthDay) => {
49 | const date = new Date(year, month, monthDay - 1, 12, 0, 0, 0)
50 | const target = new Date(date.valueOf());
51 | const dayNr = (date.getDay() + 6) % 7;
52 | target.setDate(target.getDate() - dayNr + 3);
53 | const firstThursday = target.valueOf();
54 | target.setMonth(0, 1);
55 | if (target.getDay() !== 4) {
56 | target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
57 | }
58 | return 1 + Math.ceil((firstThursday - target) / 604800000);
59 | }
60 |
61 |
62 | const allWeeks = []
63 | let monthDay = 1
64 | for (let weekIndex = 0; weekIndex < 9; weekIndex++) {
65 | const weekDays = []
66 | for (let weekDay = 0; weekDay <= 6; weekDay++) {
67 | if (isInMonth(monthDay, weekIndex, weekDay)) {
68 | weekDays.push({
69 | inMonth: true,
70 | day: monthDay
71 | })
72 | monthDay+= 1
73 | } else {
74 | weekDays.push({
75 | inMonth: false
76 | })
77 | }
78 | }
79 |
80 | const weekNum = getWeekNumber(monthDay)
81 |
82 | allWeeks.push({
83 | weekDays,
84 | weekNum
85 | })
86 |
87 | if (monthDay > monthLength) {
88 | break
89 | }
90 | }
91 |
92 | return {
93 | year, month, weeks: allWeeks
94 | }
95 |
96 | }
97 |
98 |
99 |
100 | /**
101 | calendarDays: [
102 | {weekNum: N,
103 | wekDays: [
104 | {inMonth: true, day: N, mode: ''}
105 | or
106 | {inMonth: false}
107 | ]
108 | },...
109 | ]
110 | */
111 |
112 | function _makeCalendarDays(groupByWeeks, selectedDate, minDate, maxDate) {
113 |
114 | if (groupByWeeks==undefined) {
115 | return []
116 | }
117 |
118 |
119 | const getDayMode = (day) => {
120 | const date= setTimeToNoon(new Date(groupByWeeks.year, groupByWeeks.month, day, 12, 0, 0, 0)).toISOString()
121 |
122 |
123 | const beforeMinDate = minDate!=undefined ? (Date.parse(date) < Date.parse(setTimeToNoon(new Date(minDate)))) : false
124 | const afterMaxDate = maxDate!=undefined ? (Date.parse(date) > Date.parse(setTimeToNoon(new Date(maxDate)))) : false
125 | const currentDate = setTimeToNoon(new Date())
126 | const nSelectedDate = setTimeToNoon(new Date(selectedDate))
127 |
128 | if (beforeMinDate || afterMaxDate) {
129 | return 'muted'
130 | } else if (Date.parse(date) === Date.parse(nSelectedDate)) {
131 | return 'selected'
132 | } else if (Date.parse(date) === Date.parse(currentDate)) {
133 | return 'current'
134 | } else {
135 | return 'normal'
136 | }
137 | }
138 |
139 | let calendarDays= []
140 |
141 | groupByWeeks.weeks.map(week => {
142 | const weekNum= week.weekNum
143 | const weekDays = week.weekDays.map(weekDay => {
144 | return {
145 | ...weekDay,
146 | mode: weekDay.inMonth ? getDayMode(weekDay.day) : undefined
147 | }
148 | })
149 | calendarDays.push({
150 | weekNum,
151 | weekDays
152 | })
153 | })
154 |
155 | return calendarDays
156 | }
157 |
158 | function useCalendarDays(displayDate, selectedDate, minDate, maxDate, weekStartsOn) {
159 | const [year, setYear]= useState(undefined)
160 | const [month, setMonth]= useState(undefined)
161 | const [groupByWeeks, setGroupByWeeks]= useState(undefined)
162 | const [calendarDays, setCalendarDays]= useState([])
163 |
164 |
165 | useEffect(() => {
166 | if (displayDate) {
167 | setYear(displayDate.getFullYear())
168 | setMonth(displayDate.getMonth())
169 | }
170 | }, [displayDate])
171 |
172 |
173 | useEffect(() => {
174 | setGroupByWeeks(_groupByWeeks(year, month, weekStartsOn))
175 | }, [year, month, weekStartsOn])
176 |
177 | useEffect(() => {
178 | setCalendarDays(_makeCalendarDays(groupByWeeks, selectedDate, minDate, maxDate))
179 | }, [groupByWeeks, selectedDate, minDate, maxDate])
180 |
181 |
182 | return calendarDays
183 | }
184 |
185 |
186 | export {useCalendarDays}
--------------------------------------------------------------------------------
/src/calendar/useCalendarProps.mjs:
--------------------------------------------------------------------------------
1 | import {useState, useEffect, useCallback, useRef} from 'react'
2 | import { useCustomEvents } from '../input/useCustomEvents'
3 | import { getMaybeFuncValue } from '../util/getMaybeFuncValue'
4 |
5 | // About autoFocus
6 | // We could handle by our own through ref callbacks
7 | // (https://blog.maisie.ink/react-ref-autofocus/)
8 | // But let's just use react's autoFocus attribute by now
9 |
10 |
11 |
12 | const useCalendarProps = (calendarPlacement, inputRef, autoFocus, onBlur, onFocus) => {
13 | const [open, setOpen] = useState(false)
14 |
15 | const [placement, setPlacement] = useState(getMaybeFuncValue(calendarPlacement))
16 |
17 | const hiddenInputRef = useRef()
18 | const overlayContainerRef = useRef()
19 | const popoverRef = useRef()
20 | const controlInputRef = typeof inputRef == 'object'
21 | ? inputRef
22 | : useRef(inputRef) // eslint-disable-line react-hooks/rules-of-hooks
23 |
24 | // NOTE: do we want to use the controlInput or the hiddenInput here?
25 | const [customOnBlur, customOnFocus] = useCustomEvents(/*hiddenInputRef*/ controlInputRef, onBlur, onFocus)
26 |
27 | const isOutside = useCallback((event) => {
28 | const outOfCalendar = (popoverRef?.current==undefined) || (!popoverRef?.current.contains(event.target))
29 | const outOfControlInput = (controlInputRef?.current==undefined) || (!controlInputRef.current.contains(event.target))
30 | const isOut= (outOfCalendar && outOfControlInput)
31 | return isOut
32 | }, [popoverRef, controlInputRef])
33 |
34 | // Control the click outside
35 | useEffect(() => {
36 | function handleClickOutside(event) {
37 | event.stopPropagation()
38 |
39 | if (open) {
40 | if (isOutside(event)) {
41 | setOpen(false)
42 | customOnBlur()
43 | }
44 | }
45 | }
46 |
47 | document.addEventListener("mousedown", handleClickOutside)
48 | return () => {
49 | document.removeEventListener("mousedown", handleClickOutside)
50 | }
51 | }, [open, isOutside, customOnBlur])
52 |
53 |
54 | //
55 | // This callback is bound to Calendar.Popover's toggle() method,
56 | // but seems it's unneccesary
57 | // Leaving, by now, this testimonial comments
58 | //
59 | // const handleHide = () => {
60 | // let inputFocused = false
61 | // try {
62 | // inputFocused= controlInputRef.current==document.activeElement
63 | // } catch(e) {}
64 | //
65 | // if (inputFocused) {
66 | // return
67 | // }
68 | // setOpen(false)
69 | // customOnBlur()
70 | // }
71 |
72 | const handleFocus = useCallback(() => {
73 | const nPlacement = getMaybeFuncValue(calendarPlacement)
74 | setPlacement(nPlacement)
75 |
76 | setOpen(true)
77 | customOnFocus()
78 | }, [calendarPlacement, customOnFocus])
79 |
80 | const handleBlur = useCallback((event) => {
81 | if (isOutside(event)) {
82 | setOpen(false)
83 | customOnBlur()
84 | }
85 | }, [isOutside, customOnBlur])
86 |
87 | return [hiddenInputRef, overlayContainerRef, popoverRef, controlInputRef, open, placement, handleFocus, handleBlur]
88 | }
89 |
90 | export { useCalendarProps }
91 |
92 |
--------------------------------------------------------------------------------
/src/index.mjs:
--------------------------------------------------------------------------------
1 | import {DatePicker} from './DatePicker'
2 |
3 | export {DatePicker}
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/input/InputClearButton.mjs:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {InputGroupText} from 'reactstrap'
3 |
4 | const InputClearButton = ({inputValue, disabled, clearButtonElement, onClick}) =>
5 |
6 | disabled ? null : onClick()}
8 | style = {{
9 | opacity: (inputValue && !disabled) ? 1 : 0.5,
10 | cursor:(inputValue && !disabled) ? 'pointer' : 'not-allowed',
11 | height: "100%"
12 | }}>
13 | {clearButtonElement}
14 |
15 |
16 |
17 |
18 | export {InputClearButton}
--------------------------------------------------------------------------------
/src/input/InputControlInput.mjs:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Input} from 'reactstrap'
3 |
4 | const InputControlInput = (
5 | {customControl, controlId,
6 | value, required, placeholder, inputRef, disabled,
7 | className, style, autoFocus, autoComplete, valid, invalid, onInvalid, noValidate,
8 | onKeyDown, onFocus, onBlur, onChange}) => {
9 |
10 | const validityClassNames= `${invalid===true ? 'is-invalid' : ''} ${valid===true ? 'is-valid' : ''}`
11 |
12 | if (customControl!=undefined) {
13 | return React.cloneElement(customControl, {
14 | id : controlId,
15 | value : value || '',
16 | required : required,
17 | placeholder : placeholder,
18 | ref : inputRef,
19 | disabled : disabled,
20 | className : `rdp-form-control ${className || ''} ${customControl.props.className||''} ${validityClassNames}`,
21 | style : {...customControl.props.style||{}, ...style || {}},
22 | autoComplete: autoComplete,
23 | onInvalid : onInvalid,
24 | noValidate : noValidate,
25 | onKeyDown : onKeyDown,
26 | onFocus : onFocus,
27 | onBlur : onBlur,
28 | onChange : onChange,
29 | valid : valid,
30 | invalid : invalid
31 | })
32 | }
33 |
34 | return (
35 |
57 | )
58 |
59 | }
60 |
61 | export {InputControlInput}
--------------------------------------------------------------------------------
/src/input/InputGroup.mjs:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | import {InputGroup as RSInputGroup} from 'reactstrap'
4 |
5 | const InputGroup = ({children, customInputGroup, size, inputId}) => {
6 |
7 | if (customInputGroup != undefined) {
8 | return (
9 | React.cloneElement(customInputGroup, {children: children})
10 | )
11 | }
12 |
13 | return (
14 |
19 | {children}
20 |
21 | )
22 | }
23 |
24 | export {InputGroup}
--------------------------------------------------------------------------------
/src/input/InputHidden.mjs:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const InputHidden = ({inputId, name, value, formattedValue, hiddenInputRef}) =>
4 |
13 | export {InputHidden}
14 |
--------------------------------------------------------------------------------
/src/input/InputOverlay.mjs:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const InputOverlay = ({oid, overlayContainerRef, children}) =>
4 |
8 | {children}
9 |
10 |
11 | export {InputOverlay}
12 |
--------------------------------------------------------------------------------
/src/input/useCustomEvents.mjs:
--------------------------------------------------------------------------------
1 | import {useCallback} from 'react'
2 |
3 | // NOTE: do we want to use the controlInput or the hiddenInput here?
4 | // We were previously using the hidden one, but I see no reasons.
5 | // 'change' events would make sense on the hidden input, but focus
6 | // control seems to be more on the control input.
7 | // Anyway, this is not decided here, but when calling useCustomEvents()
8 |
9 | const useCustomEvents = (inputRef, onBlur, onFocus) => {
10 | const customOnBlur = useCallback(() => {
11 |
12 | if (onBlur) {
13 | const event = document.createEvent('CustomEvent')
14 | event.initEvent('Change Date', true, false)
15 | inputRef.current.dispatchEvent(event)
16 | onBlur(event)
17 | }
18 | }, [inputRef, onBlur])
19 |
20 | const customOnFocus = useCallback(() => {
21 | if (onFocus) {
22 | const event = document.createEvent('CustomEvent')
23 | event.initEvent('Change Date', true, false)
24 | inputRef.current.dispatchEvent(event)
25 | onFocus(event)
26 | }
27 | }, [inputRef, onFocus])
28 |
29 | return [customOnBlur, customOnFocus]
30 | }
31 |
32 | export { useCustomEvents }
--------------------------------------------------------------------------------
/src/input/useDayLabels.mjs:
--------------------------------------------------------------------------------
1 | import {useState, useEffect} from 'react'
2 |
3 | const _getFixedDayLabels = (dayLabels, weekStartsOn) => {
4 | if (weekStartsOn > 1) {
5 | return dayLabels
6 | .slice(weekStartsOn)
7 | .concat(dayLabels.slice(0, weekStartsOn))
8 | }
9 |
10 | if (weekStartsOn === 1) {
11 | return dayLabels.slice(1).concat(dayLabels.slice(0,1))
12 | }
13 |
14 | return dayLabels
15 | }
16 |
17 |
18 | const useFixedDayLabels = (dayLabels, weekStartsOn) => {
19 |
20 | const [fixedDayLabels, setFixedDayLabels]= useState(_getFixedDayLabels(dayLabels, weekStartsOn))
21 |
22 | useEffect(() => {
23 | setFixedDayLabels(_getFixedDayLabels(dayLabels, weekStartsOn))
24 | }, [dayLabels, weekStartsOn])
25 |
26 | return fixedDayLabels
27 | }
28 |
29 | export {useFixedDayLabels}
--------------------------------------------------------------------------------
/src/input/useInputIds.mjs:
--------------------------------------------------------------------------------
1 | import {useState, useEffect} from 'react'
2 | import {getInstanceCount} from '../util/getInstanceCount'
3 |
4 | const _getIdSuffix = (id, name) => {
5 | // Try or props to determine elements' id suffix
6 | if (id!=undefined && id!='')
7 | return id
8 | if (name!=undefined && name!='')
9 | return name
10 | // If none was passed, use global vars
11 | const iCount= getInstanceCount()
12 | return iCount.toString()
13 | }
14 |
15 |
16 | const _getInputIds = (id, name, customControl) => {
17 | const idSuffix = _getIdSuffix(id, name)
18 | const group= `rdp-input-group-${idSuffix}`
19 | const hidden = id!=undefined ? id : `rdp-hidden-${idSuffix}`
20 | let control= `rdp-form-control-${idSuffix}`
21 | if (customControl!=undefined && customControl?.props?.id) {
22 | control= customControl.props.id
23 | }
24 | const overlay = `rdp-overlay-${idSuffix}`
25 | return [group, hidden, control, overlay]
26 | }
27 |
28 |
29 | const useInputIds = (id, name, customControl) => {
30 |
31 | const [inputIds, setInputIds]= useState(_getInputIds(id, name, customControl))
32 |
33 | useEffect(() => {
34 | setInputIds(_getInputIds(id, name, customControl))
35 | }, [id, name, customControl])
36 |
37 | return inputIds
38 | }
39 |
40 |
41 |
42 | export {useInputIds}
--------------------------------------------------------------------------------
/src/input/useInputValues.mjs:
--------------------------------------------------------------------------------
1 | import {useState, useEffect /*, useCallback*/} from 'react'
2 | import { getDateFromIsoString } from '../util/getDateFromIsoString'
3 | import { getIsoStringFromDate } from '../util/getIsoStringFromDate'
4 |
5 | const _makeInputValueString = (date, separator, dateFormat) => {
6 | const month = date.getMonth() + 1
7 | const day = date.getDate()
8 |
9 | if (dateFormat.match(/MM.DD.YYYY/)) {
10 | return (month > 9 ? month : `0${month}`) + separator + (day > 9 ? day : `0${day}`) + separator + date.getFullYear()
11 | }
12 | else if (dateFormat.match(/DD.MM.YYYY/)) {
13 | return (day > 9 ? day : `0${day}`) + separator + (month > 9 ? month : `0${month}`) + separator + date.getFullYear()
14 | }
15 | else {
16 | return date.getFullYear() + separator + (month > 9 ? month : `0${month}`) + separator + (day > 9 ? day : `0${day}`)
17 | }
18 | }
19 |
20 | const useInputValues = (controlInputRef, value, defaultValue, minDate, maxDate, dateFormat, onClear, onChange) => {
21 | const [separator, setSeparator]= useState(dateFormat.match(/[^A-Z]/)[0])
22 | const [innerValue, setInnerValue]= useState(null)
23 | const [inputValue, setInputValue]= useState(null)
24 | const [displayDate, setDisplayDate]= useState(null)
25 | const [selectedDate, setSelectedDate]= useState(null)
26 |
27 |
28 |
29 | // handle props changes
30 | useEffect(() => {
31 | setSeparator(dateFormat.match(/[^A-Z]/)[0])
32 | }, [dateFormat])
33 |
34 |
35 | // handle input values
36 | useEffect(() => {
37 | const isoString= value || defaultValue
38 | const minDate = getDateFromIsoString(minDate)
39 | const maxDate = getDateFromIsoString(maxDate)
40 |
41 |
42 |
43 | const nSelectedDate = getDateFromIsoString(isoString)
44 | const nInnerValue = getIsoStringFromDate(nSelectedDate)
45 | const nInputValue = isoString ? _makeInputValueString(nSelectedDate, separator, dateFormat) : null
46 |
47 | let nDisplayDate
48 | if (nSelectedDate) {
49 | //nDisplayDate = new Date(nSelectedDate)
50 | nDisplayDate = nSelectedDate
51 | } else {
52 | const today = getDateFromIsoString(new Date().toISOString())
53 | if (minDate && Date.parse(minDate) >= Date.parse(today)){
54 | nDisplayDate = minDate
55 | } else if (maxDate && Date.parse(maxDate) <= Date.parse(today)){
56 | nDisplayDate = maxDate
57 | } else {
58 | nDisplayDate = today
59 | }
60 | }
61 |
62 | setInnerValue(nInnerValue)
63 | setInputValue(nInputValue)
64 | setSelectedDate(nSelectedDate)
65 | setDisplayDate(nDisplayDate)
66 |
67 | }, [value, defaultValue, minDate, maxDate, separator, dateFormat])
68 |
69 | //
70 | const handleClear = /*useCallback(*/() => {
71 | if (onClear) {
72 | onClear()
73 | }
74 | else {
75 | setInnerValue(null)
76 | setInputValue(null)
77 | setSelectedDate(null)
78 | setDisplayDate(null)
79 |
80 | if (onChange) {
81 | onChange(null, null)
82 | }
83 | }
84 | }/*, [onClear, onChange])*/
85 |
86 | const handleBadInput = /*useCallback(*/(originalValue, tail= false) => {
87 |
88 | const parts = originalValue.replace(new RegExp(`[^0-9${separator}]`), '').split(separator)
89 |
90 | if (dateFormat.match(/MM.DD.YYYY/) || dateFormat.match(/DD.MM.YYYY/)) {
91 | if (parts[0] && parts[0].length > 2) {
92 | parts[1] = parts[0].slice(2) + (parts[1] || '')
93 | parts[0] = parts[0].slice(0, 2)
94 | }
95 | if (parts[1] && parts[1].length > 2) {
96 | parts[2] = parts[1].slice(2) + (parts[2] || '')
97 | parts[1] = parts[1].slice(0, 2)
98 | }
99 | if (parts[2]) {
100 | parts[2] = parts[2].slice(0,4)
101 | if (tail) {
102 | if (parts[2].length < 4) {
103 | parts[2]= parts[2].padEnd(4, '0')
104 | }
105 | }
106 | }
107 | } else {
108 | if (parts[0] && parts[0].length > 4) {
109 | parts[1] = parts[0].slice(4) + (parts[1] || '')
110 | parts[0] = parts[0].slice(0, 4)
111 | }
112 | if (parts[1] && parts[1].length > 2) {
113 | parts[2] = parts[1].slice(2) + (parts[2] || '')
114 | parts[1] = parts[1].slice(0, 2)
115 | }
116 | if (parts[2]) {
117 | parts[2] = parts[2].slice(0,2)
118 | }
119 | }
120 | const nInputValue= parts.join(separator)
121 | setInputValue(nInputValue)
122 | }/*, [dateFormat, separator])*/
123 |
124 | const handleBadInputOnBlur = () => {
125 | const originalValue = controlInputRef?.current?.value || ''
126 | if (originalValue) {
127 | handleBadInput(originalValue, true)
128 | }
129 | }
130 |
131 | const handleInputChange = /*useCallback(*/() => {
132 | const originalValue = controlInputRef?.current?.value || ''
133 | const nInputValue = originalValue.replace(/(-|\/\/)/g, separator).slice(0,10)
134 |
135 | if (!nInputValue) {
136 | handleClear()
137 | return
138 | }
139 |
140 | let month, day, year
141 | if (dateFormat.match(/MM.DD.YYYY/)) {
142 | if (!nInputValue.match(/[0-1][0-9].[0-3][0-9].[1-2][0-9][0-9][0-9]/)) {
143 | return handleBadInput(originalValue)
144 | }
145 |
146 | month = nInputValue.slice(0,2).replace(/[^0-9]/g, '')
147 | day = nInputValue.slice(3,5).replace(/[^0-9]/g, '')
148 | year = nInputValue.slice(6,10).replace(/[^0-9]/g, '')
149 | } else if (dateFormat.match(/DD.MM.YYYY/)) {
150 | if (!nInputValue.match(/[0-3][0-9].[0-1][0-9].[1-2][0-9][0-9][0-9]/)) {
151 | return handleBadInput(originalValue)
152 | }
153 |
154 | day = nInputValue.slice(0,2).replace(/[^0-9]/g, '')
155 | month = nInputValue.slice(3,5).replace(/[^0-9]/g, '')
156 | year = nInputValue.slice(6,10).replace(/[^0-9]/g, '')
157 | } else {
158 | if (!nInputValue.match(/[1-2][0-9][0-9][0-9].[0-1][0-9].[0-3][0-9]/)) {
159 | return handleBadInput(originalValue)
160 | }
161 |
162 | year = nInputValue.slice(0,4).replace(/[^0-9]/g, '')
163 | month = nInputValue.slice(5,7).replace(/[^0-9]/g, '')
164 | day = nInputValue.slice(8,10).replace(/[^0-9]/g, '')
165 | }
166 |
167 | const monthInteger = parseInt(month, 10)
168 | const dayInteger = parseInt(day, 10)
169 | const yearInteger = parseInt(year, 10)
170 | if (monthInteger > 12 || dayInteger > 31) {
171 | return handleBadInput(originalValue)
172 | }
173 |
174 | const beforeMinDate = minDate && Date.parse(originalValue) < Date.parse(minDate)
175 | const afterMaxDate = maxDate && Date.parse(originalValue) > Date.parse(maxDate)
176 |
177 | if (beforeMinDate || afterMaxDate) {
178 | return handleBadInput(originalValue)
179 | }
180 |
181 | if (!isNaN(monthInteger) && !isNaN(dayInteger) && !isNaN(yearInteger) && monthInteger <= 12 && dayInteger <= 31 && yearInteger > 999) {
182 | const nSelectedDate = getDateFromIsoString(new Date(yearInteger, monthInteger - 1, dayInteger, 12, 0, 0, 0).toISOString())
183 | const nInnerValue = getIsoStringFromDate(nSelectedDate)
184 |
185 | setSelectedDate(nSelectedDate)
186 | setDisplayDate(nSelectedDate)
187 | setInnerValue(nInnerValue)
188 |
189 | if (onChange) {
190 | onChange(nInnerValue, nInputValue)
191 | }
192 | }
193 |
194 | setInputValue(nInputValue)
195 | }/*, [controlInputRef, separator, onChange, minDate, maxDate])*/
196 |
197 | const handleChangeMonth = (nDisplayDate) => {
198 | setDisplayDate(nDisplayDate)
199 | }
200 |
201 | const handleChangeDate = /*useCallback(*/(nSelectedDate) => {
202 | const nInnerValue = getIsoStringFromDate(nSelectedDate)
203 | const nInputValue = _makeInputValueString(nSelectedDate, separator, dateFormat)
204 |
205 | setInputValue(nInputValue)
206 | setSelectedDate(nSelectedDate)
207 | setDisplayDate(nSelectedDate)
208 | setInnerValue(nInnerValue)
209 |
210 | if (onChange) {
211 | onChange(nInnerValue, nInputValue)
212 | }
213 | }/*, [separator, dateFormat, onChange])*/
214 |
215 |
216 | return [innerValue, inputValue, displayDate, selectedDate, handleClear, handleInputChange, handleChangeMonth, handleChangeDate, handleBadInputOnBlur]
217 |
218 | }
219 |
220 |
221 |
222 | export { useInputValues }
--------------------------------------------------------------------------------
/src/props.tar.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/afialapis/reactstrap-date-picker/8be567d29eee1dfe43c80524e7463b6ca9ea721f/src/props.tar.gz
--------------------------------------------------------------------------------
/src/util/compareMonths.mjs:
--------------------------------------------------------------------------------
1 | const compareMonths = (a, b) => {
2 | try {
3 | const da= new Date(a)
4 | const db= new Date(b)
5 |
6 | const sameYear= da.getFullYear() == db.getFullYear()
7 | const sameMonth = da.getMonth() == db.getMonth()
8 |
9 | return sameMonth && sameYear
10 | }catch(e) {
11 | console.error(e)
12 | return true
13 | }
14 | }
15 |
16 |
17 | export {compareMonths}
--------------------------------------------------------------------------------
/src/util/getDateFromIsoString.mjs:
--------------------------------------------------------------------------------
1 | import {setTimeToNoon} from './setTimeToNoon'
2 |
3 | const getDateFromIsoString = (isoString) =>
4 | isoString ? setTimeToNoon(new Date(isoString)) : null
5 | //isoString ? new Date(`${isoString.slice(0,10)}T12:00:00.000Z`) : null
6 |
7 |
8 | export { getDateFromIsoString }
--------------------------------------------------------------------------------
/src/util/getInstanceCount.mjs:
--------------------------------------------------------------------------------
1 | const getInstanceCount = () => {
2 | if (typeof window === 'object') {
3 | if (window._reactstrapDatePickerInstance == undefined) {
4 | window._reactstrapDatePickerInstance= 0
5 | }
6 | const next= window._reactstrapDatePickerInstance+1
7 | window._reactstrapDatePickerInstance= next
8 | return next
9 | } else if (typeof process === 'object') {
10 | if (process._reactstrapDatePickerInstance == undefined) {
11 | process._reactstrapDatePickerInstance= 0
12 | }
13 | const next= process._reactstrapDatePickerInstance+1
14 | process._reactstrapDatePickerInstance= next
15 | return next
16 | } else {
17 | console.error("Reactstrap Date Picker cannot determine environment (it is neither browser's nor Node's ).")
18 | return 1
19 | }
20 | }
21 |
22 | export {getInstanceCount}
--------------------------------------------------------------------------------
/src/util/getIsoStringFromDate.mjs:
--------------------------------------------------------------------------------
1 | import {setTimeToNoon} from './setTimeToNoon'
2 |
3 | const getIsoStringFromDate = (date) =>
4 | date ? setTimeToNoon(date).toISOString() : null
5 | //date ? `${date.toISOString().slice(0,10)}T12:00:00.000Z` : null
6 |
7 | export { getIsoStringFromDate }
--------------------------------------------------------------------------------
/src/util/getMaybeFuncValue.mjs:
--------------------------------------------------------------------------------
1 | const getMaybeFuncValue = (value) => {
2 | const tag = Object.prototype.toString.call(value)
3 | const isFunction = tag === '[object AsyncFunction]' || tag === '[object Function]' || tag === '[object GeneratorFunction]' || tag === '[object Proxy]'
4 | if (isFunction) {
5 | return value()
6 | }
7 | else {
8 | return value
9 | }
10 | }
11 |
12 |
13 | export { getMaybeFuncValue }
--------------------------------------------------------------------------------
/src/util/setTimeToNoon.mjs:
--------------------------------------------------------------------------------
1 | const setTimeToNoon = (date) => {
2 | if (! date) {
3 | return null
4 | }
5 | date.setHours(12 - date.getTimezoneOffset()/60)
6 | date.setMinutes(0)
7 | date.setSeconds(0)
8 | date.setMilliseconds(0)
9 | return date
10 | }
11 |
12 | export {setTimeToNoon}
--------------------------------------------------------------------------------
/src/util/useCheckProps.mjs:
--------------------------------------------------------------------------------
1 | const useCheckProps = (value, defaultValue) => {
2 | if (value && defaultValue) {
3 | return 'Conflicting DatePicker properties \'value\' and \'defaultValue\''
4 | }
5 |
6 | return undefined
7 | }
8 |
9 | export {useCheckProps}
--------------------------------------------------------------------------------
/src/util/useMaybeFuncProp.mjs:
--------------------------------------------------------------------------------
1 | import {useState, useEffect} from 'react'
2 | import { getMaybeFuncValue } from './getMaybeFuncValue'
3 |
4 |
5 | const useMaybeFuncProp = (propValue) => {
6 |
7 | const [value, setValue]= useState(getMaybeFuncValue(propValue))
8 |
9 | useEffect(() => {
10 | setValue(getMaybeFuncValue(propValue))
11 | }, [propValue])
12 |
13 | return [value, setValue]
14 | }
15 |
16 |
17 |
18 | export {useMaybeFuncProp}
--------------------------------------------------------------------------------
/test/README.md:
--------------------------------------------------------------------------------
1 | # Run tests
2 |
3 | 1. Clone the [reactstrap-date-picker repository](https://github.com/afialapis/reactstrap-date-picker)
4 | 2. Run `npm install` to install dependencies
5 | 3. Run `npm run test`
6 |
7 | # About `enzyme` and `cheerio`
8 |
9 | `enzyme` needs `cheerio`. At least for current `enzyme` version (3.11.0), there is an import error.
10 |
11 | We need to stick to `cheerio`'s version "1.0.0-rc.3".
12 |
13 | [More info here](https://github.com/enzymejs/enzyme/issues/2518)
14 |
15 |
--------------------------------------------------------------------------------
/test/before.mjs:
--------------------------------------------------------------------------------
1 | before(async function(){
2 | // console.log('Preloading functions (ESM) for being used in test units (CJS)')
3 |
4 | const { _resolve } = await import("./esm_pkg.cjs")
5 | await _resolve()
6 | })
7 |
8 |
--------------------------------------------------------------------------------
/test/esm_pkg.cjs:
--------------------------------------------------------------------------------
1 |
2 | "use strict";
3 |
4 | // Wrapper for dynamic import() of ESM-only packages.
5 | // Only works in later versions of Node.js 12+
6 |
7 | let _rdpPkg
8 | const _getRDPPkg = async () => {
9 | if (!_rdpPkg) {
10 | _rdpPkg = await import("../src/index.mjs");
11 | }
12 |
13 | return _rdpPkg;
14 | };
15 |
16 |
17 | const _resolve = async () => Promise.all([
18 | global.formigaRPkg = await _getRDPPkg()
19 | ]);
20 |
21 | module.exports = {
22 | _resolve,
23 | };
24 |
25 |
--------------------------------------------------------------------------------
/test/tools/checks.cjs:
--------------------------------------------------------------------------------
1 | const expect= global.expect
2 |
3 | const assertIsoStringsHaveSameDate = (IsoStringA, IsoStringB) => {
4 | const dateA = new Date(IsoStringA)
5 | const dateB = new Date(IsoStringB)
6 |
7 | expect(dateA.getMonth()).to.equal(dateB.getMonth())
8 | expect(dateA.getDate()).to.equal(dateB.getDate())
9 | expect(dateA.getFullYear()).to.equal(dateB.getFullYear())
10 | }
11 |
12 |
13 | export {assertIsoStringsHaveSameDate}
--------------------------------------------------------------------------------
/test/tools/finders.cjs:
--------------------------------------------------------------------------------
1 | const getHiddenInput = (container, did) => container.querySelector(`input#${did}`)
2 | const getHiddenInputValue = (container, did) => getHiddenInput(container, did).value
3 | const getHiddenInputFmtValue = (container, did) => getHiddenInput(container, did).getAttribute('data-formattedvalue')
4 | const getInput = (container) => container.querySelector(`input.form-control`)
5 | const getCalendar = (container) => container.querySelector(`div.rdp-popover`)
6 | const getCalendarRandomDay = (container) => container.querySelectorAll(`table tbody tr:last-child td`)[0]
7 | const getCalendarDay = (container, row, col) => container.querySelectorAll(`table tbody tr`)[row].querySelectorAll('td')[col]
8 | const getCalendarDayHeader = (container, col) => container.querySelectorAll(`table thead tr`)[0].querySelectorAll('td')[col]
9 |
10 | export {
11 | getHiddenInput,
12 | getHiddenInputValue,
13 | getHiddenInputFmtValue,
14 | getInput,
15 | getCalendar,
16 | getCalendarRandomDay,
17 | getCalendarDay,
18 | getCalendarDayHeader
19 | }
20 |
--------------------------------------------------------------------------------
/test/units/integrity/basic.cjs:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {DatePicker} from '../../../src/index'
3 | import {assertIsoStringsHaveSameDate} from '../../tools/checks'
4 |
5 | import {
6 | getHiddenInput,
7 | getHiddenInputValue,
8 | getHiddenInputFmtValue
9 | } from '../../tools/finders'
10 |
11 | const expect= global.expect
12 | const render= global.render
13 |
14 |
15 | describe('integrity: basic', function () {
16 | // this.timeout(100)
17 |
18 |
19 | it('should render a date picker', () => {
20 | const did= 'basic'
21 | const {container} = render( )
22 |
23 | // check the hidden input is actually there
24 | const hiddenInput= getHiddenInput(container, did)
25 | expect(hiddenInput).to.exist
26 |
27 | })
28 |
29 |
30 | it("should render a date picker with a value.", () => {
31 | const did = 'basic-with-value'
32 | const value = `${new Date().toISOString().slice(0,10)}T12:00:00.000Z`
33 | const Unit = () =>
34 |
35 |
36 | const {container} = render( )
37 |
38 | // get both hidden and shown values
39 | const hiddenInputValue = getHiddenInputValue(container, did)
40 | const hiddenInputFmtValue = getHiddenInputFmtValue(container, did)
41 |
42 | // check they are the same
43 | assertIsoStringsHaveSameDate(hiddenInputValue, hiddenInputFmtValue)
44 | expect(hiddenInputFmtValue)
45 | .to.equal(`${value.slice(5,7)}/${value.slice(8,10)}/${value.slice(0,4)}`)
46 | })
47 |
48 |
49 | })
--------------------------------------------------------------------------------
/test/units/integrity/calendar.cjs:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {DatePicker} from '../../../src/index'
3 | import {assertIsoStringsHaveSameDate} from '../../tools/checks'
4 |
5 | import {
6 | getHiddenInputValue,
7 | getHiddenInputFmtValue,
8 | getInput,
9 | getCalendarRandomDay,
10 | getCalendarDay,
11 | getCalendar
12 | }
13 | from '../../tools/finders'
14 |
15 | const {
16 | expect,
17 | render,
18 | fireEvent
19 | } = global
20 |
21 | describe('integrity: calendar', function () {
22 | this.timeout(5000)
23 |
24 | it("should open the calendar and select a date.", () => {
25 | const did = 'calendar-select'
26 | const Unit = () =>
27 |
28 |
29 | const {container} = render( )
30 |
31 | // check hidden input starts empty
32 | let hiddenInputValue = getHiddenInputValue(container, did)
33 | let hiddenInputFmtValue = getHiddenInputFmtValue(container, did)
34 |
35 | expect(hiddenInputValue).to.equal('')
36 | expect(hiddenInputFmtValue).to.equal('')
37 |
38 | // focus on control input, open calendar
39 | const input = getInput(container)
40 | fireEvent.focus(input)
41 |
42 | // click on some day in the calendar
43 | const day = getCalendarRandomDay(container)
44 | fireEvent.click(day)
45 |
46 | // check some value has been selected
47 | hiddenInputValue = getHiddenInputValue(container, did)
48 | hiddenInputFmtValue = getHiddenInputFmtValue(container, did)
49 |
50 | expect(hiddenInputValue).to.not.equal('')
51 | expect(hiddenInputFmtValue).to.not.equal('')
52 |
53 |
54 | })
55 |
56 | it("should open the calendar, select a date, and trigger a change event.", () => {
57 | const did = 'calendar-select'
58 |
59 | let value = null;
60 | let formattedValue = null;
61 |
62 | const Unit = () =>
63 | {value= v; formattedValue= f}}/>
64 |
65 | const {container} = render( )
66 |
67 | // focus on control input, open calendar
68 | const input = getInput(container)
69 | fireEvent.focus(input)
70 |
71 | // check values are still empty empty
72 | expect(value).to.equal(null)
73 | expect(formattedValue).to.equal(null)
74 |
75 | // click on some day in the calendar
76 | const day = getCalendarRandomDay(container)
77 | fireEvent.click(day)
78 |
79 | // check values are ok after selection
80 | expect(value).to.exist
81 | expect(formattedValue).to.exist
82 | expect(typeof value).to.equal('string')
83 | expect(typeof formattedValue).to.equal('string')
84 | assertIsoStringsHaveSameDate(value, formattedValue)
85 |
86 |
87 |
88 | })
89 |
90 | it("should open the calendar and render 29 days on a leap year.", () => {
91 | const did = 'calendar-leap-year'
92 | const value = "2016-02-15T00:00:00.000Z"
93 | const Unit = () =>
94 |
95 |
96 | const {container} = render( )
97 |
98 | // focus on control input, open calendar
99 | const input = getInput(container)
100 | fireEvent.focus(input)
101 |
102 | // get the 29th day element
103 | const day29container= getCalendarDay(container, 4, 1)
104 | expect(day29container.innerHTML).to.equal('29')
105 |
106 | // select it and check the value is ok
107 | fireEvent.click(day29container)
108 |
109 | const hiddenInputValue = getHiddenInputValue(container, did)
110 | assertIsoStringsHaveSameDate(hiddenInputValue, "2016-02-29T00:00:00.000Z")
111 |
112 |
113 | })
114 |
115 | it("should go to the previous and next month.", () => {
116 | const did = 'calendar-month-iter'
117 | const Unit = () =>
118 |
119 |
120 | const {container} = render( )
121 |
122 | // focus on control input, open calendar
123 | const input = getInput(container)
124 | fireEvent.focus(input)
125 |
126 | // find month switchers
127 | const previousButtonElement = container.querySelector(`div.rdp-header-previous-wrapper`)
128 | const nextButtonElement = container.querySelector(`div.rdp-header-next-wrapper`)
129 |
130 | // go to previous month
131 | fireEvent.click(previousButtonElement)
132 |
133 | // select any day in that month and get the value
134 | const previousDay = getCalendarRandomDay(container)
135 | fireEvent.click(previousDay)
136 | const previousMonthISOString = getHiddenInputValue(container, did)
137 |
138 | // reopen calendar
139 | fireEvent.focus(input)
140 |
141 | // go to next month
142 | fireEvent.click(nextButtonElement)
143 |
144 | // select any day in that month and get the value
145 | const nextDay = getCalendarRandomDay(container)
146 | fireEvent.click(nextDay)
147 | const currentMonthISOString = getHiddenInputValue(container, did)
148 |
149 | // check taht previous month' day is actually older
150 | expect(previousMonthISOString < currentMonthISOString).to.equal(true)
151 |
152 |
153 | })
154 |
155 | it("should cycle through every month in the year.", () => {
156 | const did = 'calendar-month-year-loop'
157 | const value = "2016-01-15T00:00:00.000Z"
158 | const Unit = () =>
159 |
160 |
161 | const {container} = render( )
162 | // focus on control input, open calendar
163 | const input = getInput(container)
164 | fireEvent.focus(input)
165 |
166 |
167 | // iter 12 months
168 | for(let monthIndex = 0; monthIndex < 12; monthIndex++) {
169 | // on the first loop we are already on the wanted month
170 | if (monthIndex>0) {
171 | // open calendar
172 | fireEvent.focus(input)
173 |
174 | // find month switchers
175 | const nextButtonElement = container.querySelector('div.rdp-header-next-wrapper')
176 | fireEvent.click(nextButtonElement)
177 | }
178 | // select any day in that month and get the value
179 | const day = getCalendarRandomDay(container)
180 | fireEvent.click(day)
181 | const randomMonthISOString = getHiddenInputValue(container, did)
182 |
183 | const randomMonthDate = new Date(randomMonthISOString)
184 | expect(randomMonthDate.getMonth()).to.equal(monthIndex)
185 | }
186 |
187 |
188 | })
189 |
190 | it("should change month and year using default pick month element.", () => {
191 | const did = 'calendar-month-iter-using-pick-month'
192 | const value = "2019-07-15T00:00:00.000Z"
193 | const minDate = "2018-07-15T00:00:00.000Z"
194 | const maxDate = "2023-07-15T00:00:00.000Z"
195 | const Unit = () =>
196 |
201 |
202 | const {container} = render( )
203 |
204 | // focus on control input, open calendar
205 | const input = getInput(container)
206 | fireEvent.focus(input)
207 |
208 | // find month switcher
209 | const pickMonthElement = container.querySelector(`div.rdp-header-pick-month-default-month select`)
210 |
211 | // go to March
212 | fireEvent.change(pickMonthElement, { target: { name: 'rdp-header-pick-month-default-month', value: 2 }})
213 |
214 | // select any day in that month and get the value
215 | const previousDay = getCalendarRandomDay(container)
216 | fireEvent.click(previousDay)
217 | const some2019MarchISOString = getHiddenInputValue(container, did)
218 |
219 | // reopen calendar
220 | fireEvent.focus(input)
221 |
222 | // find year switcher
223 | const pickYearElement = container.querySelector(`div.rdp-header-pick-month-default-year select`)
224 |
225 | // go to 2023
226 | fireEvent.change(pickYearElement, { target: { name: 'rdp-header-pick-month-default-year', value: 2023 }})
227 |
228 | // select any day in that month and get the value
229 | const nextDay = getCalendarRandomDay(container)
230 | fireEvent.click(nextDay)
231 | const some2023ISOString = getHiddenInputValue(container, did)
232 |
233 | // check taht first date is actually older
234 | expect(some2019MarchISOString < some2023ISOString).to.equal(true)
235 |
236 | // check picked dates are alright
237 | const some2019MarchDate = new Date(some2019MarchISOString)
238 | const some2023Date = new Date(some2023ISOString)
239 |
240 | expect(some2019MarchDate.getMonth()).to.equal(2)
241 | expect(some2019MarchDate.getFullYear()).to.equal(2019)
242 |
243 | expect(some2023Date.getMonth()).to.equal(2)
244 | expect(some2023Date.getFullYear()).to.equal(2023)
245 |
246 |
247 | })
248 |
249 | it("should display the correct day of the week in the calendar.", () => {
250 |
251 | const did = 'calndar-integrity-one'
252 | const Unit = () =>
253 |
256 |
257 | const {container} = render( )
258 |
259 | const input= getInput(container)
260 |
261 | const checkMonthAndYear = function(startValue) {
262 | fireEvent.change(input, {target: {value: `${startValue.slice(5,7)}/${startValue.slice(8,10)}/${startValue.slice(0,4)}`}})
263 | fireEvent.focus(input)
264 |
265 | const calendar = getCalendar(container)
266 |
267 | const weeks = calendar.querySelectorAll("table tbody tr")
268 |
269 | weeks.forEach( (week, _weekIdx) => {
270 | const days= week.querySelectorAll('td')
271 |
272 | days.forEach( (day, dayIdx) => {
273 | const dayText = day.innerHTML
274 |
275 | if (dayText !== '') {
276 |
277 | fireEvent.click(day)
278 |
279 | const hiddenInputValue = getHiddenInputValue(container, did)
280 | let date = new Date(hiddenInputValue)
281 |
282 | expect(date.getDay()).to.equal(dayIdx)
283 | }
284 | })
285 | })
286 | }
287 |
288 |
289 | // const check5Years = () => {
290 | // const today = new Date()
291 | // for(let year = today.getFullYear() - 2; year < today.getFullYear() + 2; year++) {
292 | // for(let month = 0; month < 12; month++) {
293 | // const date = new Date()
294 | // date.setMonth(month)
295 | // date.setYear(year)
296 | // checkMonthAndYear(date.toISOString())
297 | // }
298 | // }
299 | // }
300 |
301 | const checkSeveralDates = () => {
302 | checkMonthAndYear('2011-12-01T12:00:00.000Z')
303 | checkMonthAndYear('2012-11-02T12:00:00.000Z')
304 | checkMonthAndYear('2013-10-03T12:00:00.000Z')
305 | checkMonthAndYear('2014-09-04T12:00:00.000Z')
306 | checkMonthAndYear('2015-08-05T12:00:00.000Z')
307 | checkMonthAndYear('2016-07-06T12:00:00.000Z')
308 | checkMonthAndYear('2017-06-07T12:00:00.000Z')
309 | checkMonthAndYear('2018-05-08T12:00:00.000Z')
310 | checkMonthAndYear('2019-04-09T12:00:00.000Z')
311 | checkMonthAndYear('2020-03-10T12:00:00.000Z')
312 | checkMonthAndYear('2021-02-11T12:00:00.000Z')
313 | checkMonthAndYear('2022-01-12T12:00:00.000Z')
314 | }
315 |
316 | //check5Years()
317 | checkSeveralDates()
318 |
319 |
320 | })
321 | })
--------------------------------------------------------------------------------
/test/units/integrity/typing.cjs:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {DatePicker} from '../../../src/index'
3 | import {
4 | getInput
5 | } from '../../tools/finders'
6 |
7 | const {
8 | expect,
9 | render,
10 | fireEvent
11 | } = global
12 |
13 | describe('integrity: typing', function () {
14 | // this.timeout(100)
15 |
16 | it('should trim extra characters.', () => {
17 | const did = 'typing-one'
18 | const Unit = () =>
19 |
21 |
22 | const {container} = render( )
23 |
24 | const input = getInput(container)
25 |
26 | fireEvent.change(input, {target: {value: "05/31/1980 extra"}})
27 | expect(input.value).to.equal("05/31/1980")
28 | })
29 |
30 |
31 | it("should automatically insert slashes.", () => {
32 | const did = 'typing-two'
33 | const Unit = () =>
34 |
36 |
37 | const {container} = render( )
38 |
39 | const input= getInput(container)
40 |
41 | fireEvent.change(input, {target: {value: "05/31/1980 extra"}})
42 | expect(input.value).to.equal("05/31/1980")
43 |
44 | fireEvent.change(input, {target: {value: "0"}})
45 | fireEvent.change(input, {target: {value: "053"}})
46 | expect(input.value).to.equal("05/3")
47 |
48 | fireEvent.change(input, {target: {value: "05/311"}})
49 | expect(input.value).to.equal("05/31/1")
50 | })
51 | })
--------------------------------------------------------------------------------
/test/units/properties/calendar/calendarContainer.cjs:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {DatePicker} from '../../../../src/index'
3 |
4 | import {
5 | getInput
6 | } from '../../../tools/finders'
7 |
8 |
9 | const {
10 | expect,
11 | render,
12 | fireEvent
13 | } = global
14 |
15 | describe('props:calendar: calendar', function () {
16 | // this.timeout(500)
17 |
18 | it("should allow placing the popover calendar in a container specified in the props.", () => {
19 | const did = 'calendar-container'
20 |
21 | const Unit = () =>
22 | <>
23 |
24 |
26 | >
27 | const {container} = render( )
28 |
29 | const input= getInput(container)
30 | fireEvent.focus(input)
31 |
32 | // check using document
33 | const calendar= container.querySelector(`div#heyho`)
34 | expect(calendar).to.exist
35 | expect(calendar.innerHTML.indexOf('rdp-popover')>=0).to.equal(true)
36 |
37 | // NOTE Dunno if intended/expected, but trough enzyme
38 | // wrappers the calendar is always inside the DatePicker tree
39 | // const calendar= container.querySelector('div#heyho')
40 |
41 |
42 | })
43 | })
--------------------------------------------------------------------------------
/test/units/properties/calendar/calendarPlacement.cjs:
--------------------------------------------------------------------------------
1 |
2 | import React from 'react'
3 | import {DatePicker} from '../../../../src/index'
4 |
5 | import {
6 | getInput
7 | } from '../../../tools/finders'
8 |
9 | const {
10 | expect,
11 | render,
12 | fireEvent
13 | } = global
14 |
15 |
16 | describe('props:calendar: calendarPlacement', function () {
17 | // this.timeout(250)
18 |
19 | it("should allow for a string to determine calendar placement", () => {
20 | const did = 'calendar-placement-string'
21 |
22 | const Unit = () =>
23 |
26 |
27 | const {container} = render( )
28 |
29 | const input= getInput(container)
30 | fireEvent.focus(input)
31 |
32 | const calendar= container.querySelector(`div.rdp-popover.fade.right`)
33 | expect(calendar).to.exist
34 |
35 |
36 | })
37 |
38 |
39 | it("should allow for a function to determine calendar placement", () => {
40 | const did = 'calendar-placement-function'
41 | const handlePlacement = () => "top"
42 |
43 | const Unit = () =>
44 |
47 |
48 | const {container} = render( )
49 |
50 | const input= getInput(container)
51 | fireEvent.focus(input)
52 |
53 | const calendar= container.querySelector(`div.rdp-popover.fade.top`)
54 | expect(calendar).to.exist
55 |
56 |
57 | })
58 | })
--------------------------------------------------------------------------------
/test/units/properties/calendar/dayLabels.cjs:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {DatePicker} from '../../../../src/index'
3 |
4 | import {getInput, getCalendar} from '../../../tools/finders'
5 |
6 | const {
7 | expect,
8 | render,
9 | fireEvent
10 | } = global
11 |
12 |
13 | describe('props:calendar: dayLabels', function () {
14 | // this.timeout(300)
15 |
16 | it("should render custom day labels", (done) => {
17 | //// this.timeout(300)
18 |
19 | const did = 'calendar-day-labels'
20 | const valueDate = new Date('2011-10-05T14:48:00.000Z')
21 | const spanishDayLabels = ['Dom', 'Lu', 'Ma', 'Mx', 'Ju', 'Vi', 'Sab']
22 |
23 | const Unit = () =>
24 |
28 |
29 | const {container} = render( )
30 |
31 | // focus on control input, open calendar
32 | const input = getInput(container)
33 | fireEvent.focus(input)
34 |
35 | // get the calendar
36 | const calendar= getCalendar(container)
37 |
38 | // check the day titles
39 | const dayTitles= calendar.querySelectorAll('table thead tr')[0].querySelectorAll('td small')
40 |
41 | dayTitles.forEach( (dayWrap, dayIdx) => {
42 | expect(dayWrap.innerHTML).to.equal(spanishDayLabels[dayIdx])
43 | })
44 |
45 |
46 |
47 | done()
48 | })
49 |
50 | })
51 |
--------------------------------------------------------------------------------
/test/units/properties/calendar/monthLabels.cjs:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {DatePicker} from '../../../../src/index'
3 |
4 | import {getInput, getCalendar} from '../../../tools/finders'
5 |
6 | const {
7 | expect,
8 | render,
9 | fireEvent
10 | } = global
11 |
12 |
13 | describe('props:calendar: monthLabels', function () {
14 | // this.timeout(150)
15 |
16 |
17 | it("should render custom month labels", () => {
18 | const did = 'calendar-previous-button-element'
19 | const valueDate = new Date('2011-10-05T14:48:00.000Z')
20 | const spanishMonthLabels = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo',
21 | 'Junio', 'Julio', 'Agosto', 'Septiembre',
22 | 'Octubre', 'Noviembre', 'Diciembre']
23 |
24 | const Unit = () =>
25 |
29 |
30 | const {container} = render( )
31 |
32 | // focus on control input, open calendar
33 | const input = getInput(container)
34 | fireEvent.focus(input)
35 |
36 | // get the calendar
37 | const calendar= getCalendar(container)
38 |
39 | // check the month title
40 | const currentMonthLabel = spanishMonthLabels[valueDate.getMonth()]
41 | const calendarTitle = calendar.querySelector('div.rdp-header-pick-month-wrapper div').innerHTML
42 | expect(calendarTitle.indexOf(currentMonthLabel)>=0).to.equal(true)
43 |
44 |
45 | })
46 |
47 | })
--------------------------------------------------------------------------------
/test/units/properties/calendar/nextButtonElement.cjs:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {DatePicker} from '../../../../src/index'
3 |
4 | import {getInput, getCalendar} from '../../../tools/finders'
5 |
6 | const {
7 | expect,
8 | render,
9 | fireEvent
10 | } = global
11 |
12 |
13 | describe('props:calendar: nextButtonElement', function () {
14 | // this.timeout(150)
15 |
16 |
17 | it("should render custom element nextButtonElement", () => {
18 | const did = 'calendar-next-button-element'
19 | const nextButtonElement =
20 |
21 | const Unit = () =>
22 |
25 |
26 | const {container} = render( )
27 |
28 | // focus on control input, open calendar
29 | const input = getInput(container)
30 | fireEvent.focus(input)
31 |
32 | // get the calendar
33 | const calendar= getCalendar(container)
34 |
35 | // check custom button is there
36 | expect(calendar.querySelector('#custom-next-button-element')).to.exist
37 |
38 |
39 | })
40 |
41 | })
--------------------------------------------------------------------------------
/test/units/properties/calendar/pickMonthElement.cjs:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {DatePicker} from '../../../../src/index'
3 |
4 | import {getInput, getCalendar} from '../../../tools/finders'
5 |
6 | const {
7 | expect,
8 | render,
9 | fireEvent
10 | } = global
11 |
12 | describe('props:calendar: pickMonthElement', function () {
13 | // this.timeout(150)
14 |
15 |
16 | it("should render custom element pickMonthElement", () => {
17 | const did = 'calendar-previous-button-element'
18 | const pickMonthElement = () =>
19 |
20 | const Unit = () =>
21 |
24 |
25 | const {container} = render( )
26 |
27 | // focus on control input, open calendar
28 | const input = getInput(container)
29 | fireEvent.focus(input)
30 |
31 | // get the calendar
32 | const calendar= getCalendar(container)
33 |
34 | // check custom button is there
35 | expect(calendar.querySelector('#custom-pick-month-element')).to.exist
36 |
37 |
38 | })
39 |
40 | })
--------------------------------------------------------------------------------
/test/units/properties/calendar/previousButtonElement.cjs:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {DatePicker} from '../../../../src/index'
3 |
4 | import {getInput, getCalendar} from '../../../tools/finders'
5 |
6 | const {
7 | expect,
8 | render,
9 | fireEvent
10 | } = global
11 |
12 |
13 | describe('props:calendar: previousButtonElement', function () {
14 | // this.timeout(150)
15 |
16 |
17 | it("should render custom element previousButtonElement", () => {
18 | const did = 'calendar-previous-button-element'
19 | const previousButtonElement =
20 |
21 | const Unit = () =>
22 |
25 |
26 | const {container} = render( )
27 |
28 | // focus on control input, open calendar
29 | const input = getInput(container)
30 | fireEvent.focus(input)
31 |
32 | // get the calendar
33 | const calendar= getCalendar(container)
34 |
35 | // check custom button is there
36 | expect(calendar.querySelector('#custom-previous-button-element')).to.exist
37 |
38 |
39 | })
40 |
41 | })
--------------------------------------------------------------------------------
/test/units/properties/calendar/roundedCorners.cjs:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {DatePicker} from '../../../../src/index'
3 |
4 | const {
5 | expect,
6 | render,
7 | fireEvent
8 | } = global
9 |
10 |
11 | describe('props:calendar: roundedCorners', function () {
12 | // this.timeout(200)
13 |
14 | it("should allow for rounded corners.", () => {
15 | const withId = 'rdp-with-rounded-borders'
16 | const woutId = 'rdp-without-rounded-borders'
17 |
18 | const Unit = () =>
19 |
20 |
22 |
23 |
24 |
25 | const {container} = render( )
26 |
27 | const checkForInputId = (id, expected) => {
28 | // focus and open calendar
29 | const input = container.querySelector("input#rdp-form-control-" + id)
30 | fireEvent.focus(input)
31 |
32 | // get and click some day in the calendar
33 | const calendar = container.querySelector("input#" + id).closest('.input-group').querySelector('div.rdp-popover')
34 | const day= calendar.querySelectorAll(`table tbody tr:last-child td`)[0]
35 | fireEvent.click(day)
36 |
37 | // check borders on the day cell
38 | expect(day.style.borderRadius).to.equal(expected)
39 | }
40 |
41 | checkForInputId(withId, '5px')
42 | checkForInputId(woutId, '0px')
43 |
44 |
45 | })
46 |
47 | })
--------------------------------------------------------------------------------
/test/units/properties/calendar/showTodayButton.cjs:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {DatePicker} from '../../../../src/index'
3 |
4 | import {
5 | getCalendar,
6 | getInput
7 | } from '../../../tools/finders'
8 |
9 | const {
10 | expect,
11 | render,
12 | fireEvent
13 | } = global
14 |
15 |
16 | describe('props:calendar: showTodayButton / todayButtonLabel', function () {
17 | // this.timeout(150)
18 |
19 |
20 | it('should render with today button element', () => {
21 | const did = 'today-button'
22 | const todayButtonLabel = "Today is the day"
23 |
24 | const Unit = () =>
25 |
29 |
30 | const {container} = render( )
31 |
32 | // focus and open calendar
33 | const input= getInput(container)
34 | fireEvent.focus(input)
35 |
36 | // get today button
37 | const calendar= getCalendar(container)
38 | const today = calendar.querySelector('button.u-today-button')
39 |
40 | // check the label
41 | expect(today.innerHTML).to.equal(todayButtonLabel)
42 |
43 |
44 | })
45 | })
--------------------------------------------------------------------------------
/test/units/properties/calendar/weekStartsOn.cjs:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {DatePicker} from '../../../../src/index'
3 |
4 | import {
5 | getHiddenInputValue,
6 | getInput,
7 | getCalendar,
8 | getCalendarDayHeader
9 | } from '../../../tools/finders'
10 |
11 |
12 | const {
13 | expect,
14 | render,
15 | fireEvent
16 | } = global
17 |
18 |
19 | describe('props:calendar: weekStartsOn', function () {
20 | //// this.timeout(10000)
21 | this.timeout(3000)
22 |
23 | it("week should start on Monday.", () => {
24 | const did = 'week-starts-monday'
25 |
26 | const Unit = () =>
27 |
30 |
31 | const {container} = render( )
32 |
33 | // focus on control input, open calendar
34 | const input = getInput(container)
35 | fireEvent.focus(input)
36 |
37 | // get the first day header in the calendar
38 | const firstDay = getCalendarDayHeader(container, 0)
39 | expect(firstDay.querySelector('small').innerHTML).to.equal('Mon')
40 | })
41 |
42 | it("week should start on Thursday.", () => {
43 | const did = 'week-starts-thursday'
44 |
45 | const Unit = () =>
46 |
49 |
50 | const {container} = render( )
51 |
52 | // focus on control input, open calendar
53 | const input = getInput(container)
54 | fireEvent.focus(input)
55 |
56 | // get the first day header in the calendar
57 | const firstDay = getCalendarDayHeader(container, 0)
58 |
59 | expect(firstDay.querySelector('small').innerHTML).to.equal('Thu')
60 |
61 |
62 | })
63 |
64 | it("week should start on Saturday.", () => {
65 | const did = 'week-starts-saturday'
66 |
67 | const Unit = () =>
68 |
71 |
72 | const {container} = render( )
73 |
74 | // focus on control input, open calendar
75 | const input = getInput(container)
76 | fireEvent.focus(input)
77 |
78 | // get the first day header in the calendar
79 | const firstDay = getCalendarDayHeader(container, 0)
80 |
81 | expect(firstDay.querySelector('small').innerHTML).to.equal('Sat')
82 |
83 |
84 | })
85 |
86 | it("should display the correct day of the week in the calendar when starting on Monday.", () => {
87 | const did = 'correct-week-day'
88 |
89 | let _value = null;
90 | let _formattedValue = null;
91 |
92 | const Unit = () =>
93 | {_value= v; _formattedValue= f}}
95 | dateFormat="MM/DD/YYYY"
96 | weekStartsOn={1}
97 | />
98 |
99 | const {container} = render( )
100 |
101 | // get some s
102 | const input = getInput(container)
103 |
104 | const checkMonthAndYear = function(startValue) {
105 |
106 | fireEvent.change(input, {target: {value: `${startValue.slice(5,7)}/${startValue.slice(8,10)}/${startValue.slice(0,4)}`}})
107 | fireEvent.focus(input)
108 |
109 | const calendar = getCalendar(container)
110 |
111 | const weeks = calendar.querySelectorAll("table tbody tr")
112 |
113 | weeks.forEach( (week, _weekIdx) => {
114 | const days= week.querySelectorAll('td')
115 |
116 | days.forEach( (day, dayIdx) => {
117 | const dayText = day.innerHTML
118 |
119 | if (dayText !== '') {
120 |
121 | fireEvent.click(day)
122 |
123 | const hiddenInputValue = getHiddenInputValue(container, did)
124 | let date = new Date(hiddenInputValue)
125 |
126 | const dayN= dayIdx === 6 ? 0 : dayIdx + 1
127 | expect(date.getDay()).to.equal(dayN)
128 | }
129 | })
130 | })
131 | }
132 |
133 | // const check5Years = () => {
134 | // const today = new Date()
135 | // for(let year = today.getFullYear() - 2; year < today.getFullYear() + 2; year++) {
136 | // for(let month = 0; month < 12; month++) {
137 | // const date = new Date()
138 | // date.setMonth(month)
139 | // date.setYear(year)
140 | // checkMonthAndYear(date.toISOString())
141 | // }
142 | // }
143 | // }
144 |
145 | const checkSeveralDates = () => {
146 | checkMonthAndYear('2011-12-01T12:00:00.000Z')
147 | checkMonthAndYear('2012-11-02T12:00:00.000Z')
148 | checkMonthAndYear('2013-10-03T12:00:00.000Z')
149 | checkMonthAndYear('2014-09-04T12:00:00.000Z')
150 | checkMonthAndYear('2015-08-05T12:00:00.000Z')
151 | checkMonthAndYear('2016-07-06T12:00:00.000Z')
152 | checkMonthAndYear('2017-06-07T12:00:00.000Z')
153 | checkMonthAndYear('2018-05-08T12:00:00.000Z')
154 | checkMonthAndYear('2019-04-09T12:00:00.000Z')
155 | checkMonthAndYear('2020-03-10T12:00:00.000Z')
156 | checkMonthAndYear('2021-02-11T12:00:00.000Z')
157 | checkMonthAndYear('2022-01-12T12:00:00.000Z')
158 | }
159 |
160 | //check5Years()
161 | checkSeveralDates()
162 |
163 |
164 | })
165 | })
--------------------------------------------------------------------------------
/test/units/properties/events/changes.cjs:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {DatePicker} from '../../../../src/index'
3 |
4 | import {
5 | getInput,
6 | getCalendarRandomDay
7 | } from '../../../tools/finders'
8 |
9 | const {
10 | expect,
11 | render,
12 | fireEvent
13 | } = global
14 |
15 |
16 | describe('props:events: changes', function () {
17 | // this.timeout(500)
18 |
19 | it("should update via a change handler when the input is changed.", () => {
20 | const did = 'changes-one'
21 | let value = null;
22 | let formattedValue = null;
23 |
24 | const Unit = () =>
25 | {value= v; formattedValue= f}}
27 | dateFormat="MM/DD/YYYY"
28 | />
29 |
30 | const {container} = render( )
31 |
32 | const input= getInput(container)
33 |
34 | fireEvent.change(input, {target: {value: "05/31/1980"}})
35 |
36 | const date = new Date(value)
37 | expect(date.getMonth() ).to.equal(4)
38 | expect(date.getDate() ).to.equal(31)
39 | expect(date.getFullYear()).to.equal(1980)
40 | expect(formattedValue ).to.equal("05/31/1980")
41 | })
42 |
43 | it("should update via a change handler when cleared.", () => {
44 | const did = 'changes-two'
45 | let value = null;
46 | let formattedValue = null;
47 |
48 | const Unit = () =>
49 | {value= v; formattedValue= f}}
51 | dateFormat="MM/DD/YYYY"
52 | />
53 |
54 | const {container} = render( )
55 |
56 | const input= getInput(container)
57 | fireEvent.focus(input)
58 |
59 | const clearButton = container.querySelector("span.input-group-text")
60 | const day= getCalendarRandomDay(container)
61 |
62 | fireEvent.click(day)
63 | expect(value ).to.exist
64 | expect(formattedValue).to.exist
65 |
66 | fireEvent.click(clearButton)
67 | expect(value ).to.equal(null)
68 | expect(formattedValue).to.equal(null)
69 |
70 |
71 | })
72 | })
--------------------------------------------------------------------------------
/test/units/properties/events/focus.cjs:
--------------------------------------------------------------------------------
1 | import React, {useState} from 'react'
2 | import {DatePicker} from '../../../../src/index'
3 | import {assertIsoStringsHaveSameDate} from '../../../tools/checks'
4 |
5 | import {
6 | getInput
7 | } from '../../../tools/finders'
8 |
9 | const {
10 | expect,
11 | render,
12 | fireEvent
13 | } = global
14 |
15 |
16 | describe('props:events: focus', function () {
17 | // this.timeout(500)
18 |
19 |
20 | it("should call focus and blur handlers.", () => {
21 | const did = 'focus-one'
22 | let value = `${new Date().toISOString().slice(0,10)}T12:00:00.000Z`
23 |
24 | const Unit = () => {
25 | const [focused, setFocused]= useState(false)
26 | const [foo, _setFoo]= useState('foo')
27 |
28 | const focusHandler = (e) => {
29 | //expect(e.target).to.equal(container.querySelector("input[type=hidden]"))
30 | expect(e.target).to.equal(container.querySelector("input.form-control"))
31 | assertIsoStringsHaveSameDate(e.target.value, value)
32 | setFocused(true)
33 | }
34 |
35 | const blurHandler = (e) => {
36 | //expect(e.target).to.equal(container.querySelector("input[type=hidden]"))
37 | expect(e.target).to.equal(container.querySelector("input.form-control"))
38 | assertIsoStringsHaveSameDate(e.target.value, value)
39 | setFocused(false)
40 | }
41 |
42 | return (
43 |
44 |
45 |
setFocused(false)}
48 | onClick={() => setFocused(false)}>
49 | {focused
50 | ?
Focused
51 | :
Blurred
52 | }
53 |
54 |
blurHandler(e)}
56 | onFocus= {(e) => focusHandler(e)}
57 | value = {value} />
58 |
59 | )
60 | }
61 |
62 | const {container} = render( )
63 | const input= getInput(container)
64 |
65 | const focus_it = () => {
66 | input.focus()
67 | fireEvent.focus(input) // This is not enough to update document.activeElement, dunno why yet
68 | }
69 |
70 | const check_it_is_blurred_soft = () => expect(container.querySelector('div#blurred').length, 'checking blurred (soft)').to.not.equal(0)
71 | const check_it_is_focused_soft = () => expect(container.querySelector('div#focused').length, 'checking focused (soft)').to.not.equal(0)
72 |
73 | const check_it_is_blurred_hard = () => expect(input, 'checking blurred (hard)').to.not.equal(document.activeElement)
74 | const check_it_is_focused_hard = () => expect(input, 'checking focused (hard)').to.equal(document.activeElement)
75 |
76 | // It should start blurred
77 | check_it_is_blurred_soft()
78 | check_it_is_blurred_hard()
79 |
80 | // Let's focus it
81 | focus_it()
82 | check_it_is_focused_soft()
83 | check_it_is_focused_hard()
84 |
85 | // Let's blur it by focusing external element
86 | const blurringClick = container.querySelector('input#blurringClickTarget')
87 | blurringClick.focus()
88 | fireEvent.focus(blurringClick)
89 |
90 | check_it_is_blurred_soft()
91 | check_it_is_blurred_hard()
92 |
93 |
94 | })
95 | })
--------------------------------------------------------------------------------
/test/units/properties/globals/clearButtonElement.cjs:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {DatePicker} from '../../../../src/index'
3 |
4 | const {
5 | expect,
6 | render
7 | } = global
8 |
9 | describe('props:globals: clearButtonElement', function () {
10 | // this.timeout(100)
11 |
12 |
13 | it("should render with custom elements", () => {
14 | const did = 'clear-button'
15 | const clearButtonElement =
16 | const valueDate= new Date('2011-10-05T14:48:00.000Z')
17 |
18 | const Unit = () =>
19 |
23 |
24 | const {container} = render( )
25 |
26 | const clear= container.querySelector('#clear-button-element')
27 | expect(clear).to.exist
28 |
29 |
30 | })
31 |
32 |
33 | it("should render without clear button element", () => {
34 | const did = 'clear-button-hidden'
35 | const clearButtonElement =
36 | const valueDate= new Date('2011-10-05T14:48:00.000Z')
37 |
38 | const Unit = () =>
39 |
44 |
45 | const {container} = render( )
46 |
47 | const clear= container.querySelector('#clear-button-element')
48 | expect(clear).to.not.exist
49 | })
50 | })
--------------------------------------------------------------------------------
/test/units/properties/globals/dateFormat.cjs:
--------------------------------------------------------------------------------
1 | import React, {useState, useRef} from 'react'
2 | import {DatePicker} from '../../../../src/index'
3 | import {assertIsoStringsHaveSameDate} from '../../../tools/checks'
4 |
5 | import {
6 | getInput
7 | } from '../../../tools/finders'
8 |
9 | const {
10 | expect,
11 | render,
12 | fireEvent
13 | } = global
14 |
15 |
16 | describe('props:globals: dateFormat', function () {
17 | // this.timeout(500)
18 |
19 | it("should automatically insert in YYYY/MM/DD format.", () => {
20 | const did = 'date-formats-one'
21 | const Unit = () =>
22 |
25 |
26 | const {container} = render( )
27 |
28 | const input= getInput(container)
29 |
30 | fireEvent.change(input, {target: {value: '0'}})
31 |
32 | fireEvent.change(input, {target: {value: '19800'}})
33 | expect(input.value).to.equal('1980/0')
34 |
35 | fireEvent.change(input, {target: {value: '1980/053'}})
36 | expect(input.value).to.equal('1980/05/3')
37 | })
38 |
39 | it("should render dates in different formats.", () => {
40 | const FORMATS= {
41 | d1: 'MM/DD/YYYY',
42 | d2: 'DD/MM/YYYY',
43 | d3: 'YYYY/MM/DD'
44 | }
45 | const did1 = 'date-formats-d1'
46 | const did2 = 'date-formats-d2'
47 | const did3 = 'date-formats-d3'
48 | const values = {}
49 | const formattedValues= {}
50 | const getValues = {}
51 | const getFormattedValues= {}
52 |
53 | const Unit = () => {
54 | const [value1, setValue1]= useState(null)
55 | const [value2, setValue2]= useState(null)
56 | const [value3, setValue3]= useState(null)
57 |
58 | const ref1= useRef()
59 | const ref2= useRef()
60 | const ref3= useRef()
61 |
62 | const handleCLick = () => {
63 | if (ref1.current) {
64 | getValues[FORMATS.d1] = ref1.current.getValue()
65 | getFormattedValues[FORMATS.d1] = ref1.current.getFormattedValue()
66 | }
67 |
68 | if (ref2.current) {
69 | getValues[FORMATS.d2] = ref2.current.getValue()
70 | getFormattedValues[FORMATS.d2] = ref2.current.getFormattedValue()
71 | }
72 |
73 | if (ref3.current) {
74 | getValues[FORMATS.d3] = ref3.current.getValue()
75 | getFormattedValues[FORMATS.d3] = ref3.current.getFormattedValue()
76 | }
77 | }
78 |
79 | return (
80 | <>
81 | {setValue1(v); values[FORMATS.d1] = v; formattedValues[FORMATS.d1]= f}}
86 | value = {value1}/>
87 | {setValue2(v); values[FORMATS.d2] = v; formattedValues[FORMATS.d2]= f}}
92 | value = {value2}/>
93 | {setValue3(v); values[FORMATS.d3] = v; formattedValues[FORMATS.d3]= f}}
98 | value = {value3}/>
99 |
100 | >
101 | )}
102 |
103 | const {container} = render( )
104 |
105 | const button = container.querySelector("button#test-button")
106 | const inputD1 = container.querySelector("input#rdp-form-control-" + did1)
107 | const inputD2 = container.querySelector("input#rdp-form-control-" + did2)
108 | const inputD3 = container.querySelector("input#rdp-form-control-" + did3)
109 |
110 | const checkDate = (isoString, fmt1, fmt2, fmt3) => {
111 | fireEvent.focus(inputD1)
112 | fireEvent.change(inputD1, {target: {value: fmt1}})
113 | fireEvent.focus(inputD2)
114 | fireEvent.change(inputD2, {target: {value: fmt2}})
115 | fireEvent.focus(inputD3)
116 | fireEvent.change(inputD3, {target: {value: fmt3}})
117 |
118 | fireEvent.click(button)
119 |
120 | expect(inputD1.value).to.equal(fmt1)
121 | expect(inputD2.value).to.equal(fmt2)
122 | expect(inputD3.value).to.equal(fmt3)
123 |
124 | assertIsoStringsHaveSameDate(isoString, values[FORMATS.d1])
125 | assertIsoStringsHaveSameDate(isoString, values[FORMATS.d2])
126 | assertIsoStringsHaveSameDate(isoString, values[FORMATS.d3])
127 | assertIsoStringsHaveSameDate(isoString, getValues[FORMATS.d1])
128 | assertIsoStringsHaveSameDate(isoString, getValues[FORMATS.d2])
129 | assertIsoStringsHaveSameDate(isoString, getValues[FORMATS.d3])
130 |
131 | expect(formattedValues[FORMATS.d1]).to.equal(fmt1)
132 | expect(formattedValues[FORMATS.d2]).to.equal(fmt2)
133 | expect(formattedValues[FORMATS.d3]).to.equal(fmt3)
134 | expect(getFormattedValues[FORMATS.d1]).to.equal(fmt1)
135 | expect(getFormattedValues[FORMATS.d2]).to.equal(fmt2)
136 | expect(getFormattedValues[FORMATS.d3]).to.equal(fmt3)
137 | }
138 |
139 | checkDate("1980-05-31T12:00:00.000Z", "05/31/1980", "31/05/1980", "1980/05/31")
140 | checkDate("2015-04-15T12:00:00.000Z", "04/15/2015", "15/04/2015", "2015/04/15")
141 | checkDate("1999-12-31T12:00:00.000Z", "12/31/1999", "31/12/1999", "1999/12/31")
142 | })
143 | })
--------------------------------------------------------------------------------
/test/units/properties/globals/defaultValue.cjs:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {DatePicker} from '../../../../src/DatePicker'
3 | import {assertIsoStringsHaveSameDate} from '../../../tools/checks'
4 |
5 | import {
6 | getHiddenInputValue,
7 | getInput
8 | } from '../../../tools/finders'
9 |
10 | const {
11 | expect,
12 | render,
13 | fireEvent
14 | } = global
15 |
16 | describe('props:globals: defaultValue', function () {
17 | // this.timeout(100)
18 |
19 |
20 | it("should set a default value", () => {
21 | const did = 'default-value-one'
22 | const defaultValue = `2022-05-31T12:00:00.000Z`
23 | const defaultValueFmt = `31/05/2022`
24 |
25 | const Unit = () =>
26 |
30 |
31 | const {container} = render( )
32 | const input = getInput(container)
33 |
34 | assertIsoStringsHaveSameDate(getHiddenInputValue(container, did), defaultValue)
35 | expect(input.value).to.equal(defaultValueFmt)
36 |
37 | fireEvent.change(input)
38 |
39 | assertIsoStringsHaveSameDate(getHiddenInputValue(container, did), defaultValue)
40 | expect(input.value).to.equal(defaultValueFmt)
41 |
42 | })
43 |
44 |
45 | it("should error if value and default value are both set.", () => {
46 | const did = 'default-value-two'
47 | const value = `2022-05-31T12:00:00.000Z`
48 |
49 | let errorProduced= false
50 | try {
51 | // since we use forwardRef, we have the .render() method available
52 | DatePicker.render({id: did, defaultValue: value, value: value })
53 | } catch(e) {
54 | errorProduced= true
55 | expect(e.message).to.equal("Conflicting DatePicker properties 'value' and 'defaultValue'")
56 | }
57 |
58 | expect(errorProduced).to.equal(true)
59 | })
60 |
61 | })
--------------------------------------------------------------------------------
/test/units/properties/globals/minMaxDate.cjs:
--------------------------------------------------------------------------------
1 |
2 | import React, {useState} from 'react'
3 | import {DatePicker} from '../../../../src/index'
4 |
5 | import {
6 | getHiddenInputValue,
7 | getInput,
8 | getCalendarDay
9 | } from '../../../tools/finders'
10 |
11 | const {
12 | expect,
13 | render,
14 | fireEvent
15 | } = global
16 |
17 |
18 | describe('props:globals: minDate / maxDate', function () {
19 | // this.timeout(150)
20 |
21 | it("should disable dates outside of min and max dates.", () => {
22 | const did = 'min-max-dates-one'
23 | const originalValue = "2016-09-15T12:00:00.000Z"
24 | const minDate = "2016-09-12T00:00:00.000Z"
25 | const maxDate = "2016-09-18T00:00:00.000Z"
26 | const justRightValue = "2016-09-12T12:00:00.000Z"
27 |
28 | const Unit = () => {
29 | const [value, setValue]= useState(originalValue)
30 | return (
31 | setValue(v)}
34 | minDate={minDate}
35 | maxDate={maxDate}
36 | />
37 | )
38 | }
39 |
40 | const {container} = render( )
41 |
42 |
43 | const input= getInput(container)
44 | fireEvent.focus(input)
45 |
46 | const tooEarlyDay = getCalendarDay(container, 1, 1)
47 | const justRightDay = getCalendarDay(container, 2, 1)
48 | const tooLateDay = getCalendarDay(container, 3, 1)
49 |
50 | expect(tooEarlyDay.classList.contains('text-muted')).to.equal(true)
51 | expect(justRightDay.classList.contains('text-muted')).to.equal(false)
52 | expect(tooLateDay.classList.contains('text-muted')).to.equal(true)
53 |
54 |
55 | expect(getHiddenInputValue(container, did)).to.equal(originalValue)
56 |
57 | fireEvent.click(tooEarlyDay)
58 | expect(getHiddenInputValue(container, did)).to.equal(originalValue)
59 |
60 | fireEvent.click(justRightDay)
61 | expect(getHiddenInputValue(container, did)).to.equal(justRightValue)
62 |
63 | fireEvent.click(tooLateDay)
64 | expect(getHiddenInputValue(container, did)).to.equal(justRightValue)
65 |
66 |
67 |
68 | })
69 |
70 | it("should show next and prev buttons if min and max dates are not set.", () => {
71 | const did = 'min-max-dates-two'
72 | const displayDate = "2017-07-21T12:00:00.000Z"
73 |
74 | const Unit = () => {
75 | const [value, setValue]= useState(displayDate)
76 | return (
77 | setValue(v)}
80 | />
81 | )
82 | }
83 |
84 | const {container} = render( )
85 |
86 | // focus
87 | const input= getInput(container)
88 | fireEvent.focus(input)
89 |
90 | // check buttons
91 | const prevButton = container.querySelector("div.rdp-header-previous-wrapper")
92 | const nextButton = container.querySelector("div.rdp-header-next-wrapper")
93 |
94 | expect(prevButton.innerHTML).to.equal('<')
95 | expect(nextButton.innerHTML).to.equal('>')
96 |
97 |
98 | })
99 |
100 |
101 | it("should not show next and prev buttons if min and max dates are set and limit to current month.", () => {
102 | const did = 'min-max-dates-three'
103 | const displayDate = "2017-07-21T12:00:00.000Z"
104 | const minDate = "2017-07-01T12:00:00.000Z"
105 | const maxDate = "2017-07-31T12:00:00.000Z"
106 |
107 | const Unit = () => {
108 | const [value, setValue]= useState(displayDate)
109 | return (
110 | setValue(v)}
113 | minDate={minDate}
114 | maxDate={maxDate}
115 | />
116 | )
117 | }
118 |
119 | const {container} = render( )
120 |
121 | // focus
122 | const input= getInput(container)
123 | fireEvent.focus(input)
124 |
125 | // check buttons
126 | const prevButton = container.querySelector("div.rdp-header-previous-wrapper")
127 | const nextButton = container.querySelector("div.rdp-header-next-wrapper")
128 |
129 | expect(prevButton.innerHTML).to.equal('')
130 | expect(nextButton.innerHTML).to.equal('')
131 |
132 |
133 | })
134 |
135 |
136 | it("should hide previousButtonElement if min date is set and being displayed.", () => {
137 | const did = 'min-max-dates-four'
138 | const displayDate = "2017-07-21T12:00:00.000Z"
139 | const minDate = "2017-07-01T12:00:00.000Z"
140 | const maxDate = "2017-12-31T12:00:00.000Z"
141 |
142 | const Unit = () => {
143 | const [value, setValue]= useState(displayDate)
144 | return (
145 | setValue(v)}
148 | minDate={minDate}
149 | maxDate={maxDate}
150 | />
151 | )
152 | }
153 |
154 | const {container} = render( )
155 |
156 | // focus
157 | const input= getInput(container)
158 | fireEvent.focus(input)
159 |
160 | // check buttons
161 | const prevButton = container.querySelector("div.rdp-header-previous-wrapper")
162 | const nextButton = container.querySelector("div.rdp-header-next-wrapper")
163 |
164 | expect(prevButton.innerHTML).to.equal('')
165 | expect(nextButton.innerHTML).to.equal('>')
166 |
167 |
168 | })
169 |
170 |
171 | it("should hide nextButtonElement if max date is set and being displayed.", () => {
172 | const did = 'min-max-dates-five'
173 | const displayDate = "2017-07-21T12:00:00.000Z"
174 | const minDate = "2017-01-01T12:00:00.000Z"
175 | const maxDate = "2017-07-31T12:00:00.000Z"
176 |
177 | const Unit = () => {
178 | const [value, setValue]= useState(displayDate)
179 | return (
180 | setValue(v)}
183 | minDate={minDate}
184 | maxDate={maxDate}
185 | />
186 | )
187 | }
188 |
189 | const {container} = render( )
190 |
191 | // focus
192 | const input= getInput(container)
193 | fireEvent.focus(input)
194 |
195 | // check buttons
196 | const prevButton = container.querySelector("div.rdp-header-previous-wrapper")
197 | const nextButton = container.querySelector("div.rdp-header-next-wrapper")
198 |
199 | expect(prevButton.innerHTML).to.equal('<')
200 | expect(nextButton.innerHTML).to.equal('')
201 |
202 |
203 | })
204 | })
--------------------------------------------------------------------------------
/test/units/properties/input/(in)valid.cjs:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {DatePicker} from '../../../../src/index'
3 | import {
4 | getInput
5 | } from '../../../tools/finders'
6 |
7 | const {
8 | expect,
9 | render
10 | } = global
11 |
12 | describe('props:input: valid/invalid', function () {
13 | // this.timeout(100)
14 |
15 | it("should not include the is-invalid class when invalid is false", () => {
16 |
17 | const did = 'check-invalid-one'
18 |
19 | const Unit = () =>
20 |
23 |
24 | const {container} = render( )
25 |
26 | const input= getInput(container)
27 | expect(input.classList.contains('is-invalid')).to.equal(false)
28 |
29 |
30 | })
31 |
32 | it("should include the is-invalid class when invalid is true", () => {
33 | const did = 'check-invalid-two'
34 |
35 | const Unit = () =>
36 |
39 |
40 | const {container} = render( )
41 |
42 | const input= getInput(container)
43 | expect(input.classList.contains('is-invalid')).to.equal(true)
44 |
45 |
46 | })
47 |
48 | it("should not include the is-valid class when invalid is false", () => {
49 | const did = 'check-invalid-three'
50 |
51 | const Unit = () =>
52 |
55 |
56 | const {container} = render( )
57 |
58 | const input= getInput(container)
59 | expect(input.classList.contains('is-valid')).to.equal(false)
60 |
61 |
62 | })
63 |
64 | it("should include the is-valid class when invalid is true", () => {
65 | const did = 'check-invalid-four'
66 |
67 | const Unit = () =>
68 |
71 |
72 | const {container} = render( )
73 |
74 | const input= getInput(container)
75 | expect(input.classList.contains('is-valid')).to.equal(true)
76 |
77 |
78 | })
79 | })
--------------------------------------------------------------------------------
/test/units/properties/input/autoFocus.cjs:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {DatePicker} from '../../../../src/index'
3 |
4 | import {
5 | getInput
6 | } from '../../../tools/finders'
7 |
8 | const {
9 | expect,
10 | render
11 | } = global
12 |
13 | describe('props:input: autoFocus', function () {
14 | // this.timeout(100)
15 |
16 |
17 | it("should have no focus with autoFocus false.", () => {
18 | const did = 'auto-focus-no'
19 | const valueDate= new Date('2011-10-05T14:48:00.000Z')
20 |
21 | const Unit = () =>
22 |
26 |
27 | const {container} = render( )
28 |
29 | const input= getInput(container)
30 |
31 | // activeElement seems not working on RTL
32 | // expect(input).to.not.equal(container.activeElement)
33 |
34 | expect(input.matches(':focus')).to.be.false
35 |
36 | })
37 |
38 | it("should have focus with autoFocus true.", () => {
39 | const did = 'auto-focus-yes'
40 | const valueDate= new Date('2011-10-05T14:48:00.000Z')
41 |
42 | const Unit = () =>
43 |
47 |
48 | const {container} = render( )
49 |
50 | const input= getInput(container)
51 |
52 | // activeElement seems not working on RTL
53 | // expect(input).to.equal(container.activeElement)
54 |
55 | expect(input.matches(':focus')).to.be.true
56 |
57 |
58 | })
59 | })
--------------------------------------------------------------------------------
/test/units/properties/input/className.cjs:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {DatePicker} from '../../../../src/index'
3 |
4 | import {
5 | getInput
6 | } from '../../../tools/finders'
7 |
8 | const {
9 | expect,
10 | render
11 | } = global
12 |
13 |
14 | describe('props:input: className', function () {
15 | // this.timeout(100)
16 |
17 |
18 | it("should set the FormControl className.", () => {
19 | const did = 'className'
20 | const className= 'custom-rdp-classname'
21 |
22 | const Unit = () =>
23 |
26 |
27 | const {container} = render( )
28 |
29 | const input= getInput(container)
30 | expect(input.className.indexOf(className)).to.above(0)
31 | expect(container.querySelector(`input.${className}`)).to.exist
32 |
33 |
34 | })
35 | })
--------------------------------------------------------------------------------
/test/units/properties/input/customControl.cjs:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {DatePicker} from '../../../../src/index'
3 |
4 | const {
5 | expect,
6 | render
7 | } = global
8 |
9 | describe('props:input: customControl', function () {
10 | // this.timeout(100)
11 |
12 | it('should render a custom button element', () => {
13 | const did = 'custom-control'
14 |
15 | const Unit = () =>
16 | Test button }
18 | />
19 |
20 | const {container} = render( )
21 |
22 | const customControl = container.querySelector('button#test-btn')
23 |
24 | expect(customControl).to.exist
25 | expect(customControl.innerHTML).to.equal('Test button')
26 | })
27 | })
--------------------------------------------------------------------------------
/test/units/properties/input/disabled.cjs:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {DatePicker} from '../../../../src/index'
3 | import {assertIsoStringsHaveSameDate} from '../../../tools/checks'
4 |
5 | import {
6 | getInput
7 | } from '../../../tools/finders'
8 |
9 | const {
10 | expect,
11 | render,
12 | fireEvent
13 | } = global
14 |
15 | describe('props:input: disabled', function () {
16 | // this.timeout(100)
17 |
18 | it("should disable the input.", () => {
19 | const did = 'disabled-one'
20 | const valueDate= new Date('2011-10-05T14:48:00.000Z')
21 |
22 | const Unit = () =>
23 |
27 |
28 | const {container} = render( )
29 |
30 | const input= getInput(container)
31 | expect(input.disabled).to.equal(true)
32 |
33 |
34 | })
35 |
36 | it("should disable the input and ensure clear button is not clickable.", () => {
37 | const did = 'disabled-two'
38 | let valueDate= new Date('2011-10-05T14:48:00.000Z')
39 | const originalValue= valueDate.toISOString()
40 |
41 | const Unit = () =>
42 | valueDate = v}
46 | />
47 |
48 | const {container} = render( )
49 |
50 | const input= getInput(container)
51 | expect(input.disabled).to.equal(true)
52 |
53 | const clearButton = container.querySelector("span.input-group-text")
54 | fireEvent.click(clearButton)
55 |
56 | assertIsoStringsHaveSameDate(valueDate, originalValue)
57 |
58 |
59 | })
60 | })
--------------------------------------------------------------------------------
/test/units/properties/input/inputRef.cjs:
--------------------------------------------------------------------------------
1 | import React, {useState, useRef} from 'react'
2 | import {DatePicker} from '../../../../src/index'
3 |
4 | import {
5 | getInput
6 | } from '../../../tools/finders'
7 |
8 | const {
9 | expect,
10 | render,
11 | fireEvent
12 | } = global
13 |
14 |
15 | describe('props:input: inputRef', function () {
16 | // this.timeout(500)
17 |
18 |
19 | it("should check a forwarded ref and inputRef both points to the same element", () => {
20 | const did = 'using-input-ref'
21 |
22 | const Unit = () => {
23 | const [value, setValue]= useState('2015-04-15T12:00:00.000Z')
24 |
25 | const mainRef= useRef()
26 | const inputRef= useRef()
27 |
28 | const handleChange = (newValue) => {
29 | setValue(newValue)
30 | expect(mainRef.current.getNode()).to.equal(inputRef.current)
31 | }
32 |
33 | return (
34 | <>
35 | handleChange(v)}
40 | value = {value}/>
41 | >
42 | )}
43 |
44 | const {container} = render( )
45 |
46 | const input= getInput(container)
47 | fireEvent.focus(input)
48 |
49 | fireEvent.change(input, {target: {value: '01/01/2000'}})
50 |
51 | fireEvent.change(input, {target: {value: '01/01/2000'}})
52 |
53 |
54 | })
55 | })
--------------------------------------------------------------------------------
/test/units/properties/input/style.cjs:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {DatePicker} from '../../../../src/index'
3 |
4 | import {
5 | getInput,
6 | } from '../../../tools/finders'
7 |
8 | const {
9 | expect,
10 | render
11 | } = global
12 |
13 | describe('props:input: style', function () {
14 | // this.timeout(100)
15 |
16 | it("should set the FormControl style.", () => {
17 | const did = 'style'
18 | const backgroundColor = `rgb(${Math.round(Math.random() * 255, 0)}, ${Math.round(Math.random() * 255, 0)}, ${Math.round(Math.random() * 255, 0)})`
19 |
20 | const Unit = () =>
21 |
24 |
25 | const {container} = render( )
26 |
27 | const input= getInput(container)
28 | expect(input.style.backgroundColor).to.equal(backgroundColor)
29 |
30 |
31 | })
32 |
33 | })
--------------------------------------------------------------------------------
/test/units/properties/inputGroup/customInputGroup.cjs:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {DatePicker} from '../../../../src/index'
3 |
4 | import {
5 | getInput
6 | } from '../../../tools/finders'
7 |
8 | const {
9 | expect,
10 | render
11 | } = global
12 |
13 |
14 | describe('props:inputGroup: customInputGroup', function () {
15 | // this.timeout(100)
16 |
17 |
18 | it('should render a custom inpupt group element', () => {
19 | const did = 'custom-input-group-hidden'
20 |
21 | const Unit = () =>
22 | }
24 | />
25 |
26 | const {container} = render( )
27 |
28 | const customIGroup = container.querySelector('#custom-input-group')
29 | expect(customIGroup).to.exist
30 |
31 | const input= getInput(container)
32 | expect(input).to.exist
33 |
34 |
35 | })
36 | })
--------------------------------------------------------------------------------
/xeira.json:
--------------------------------------------------------------------------------
1 | {
2 | "product": "package",
3 | "target": "both",
4 | "source_index": "./src/index.mjs",
5 | "linter": "eslint",
6 | "transpile_folder": "./lib",
7 | "transpiler": "babel",
8 | "minifier": "none",
9 | "bundle_folder": "./dist",
10 | "bundler": "rollup",
11 | "test_folder": "./test",
12 | "demo_mode": "auto",
13 | "demo_demoer": "rollup",
14 | "verbose": false
15 | }
16 |
--------------------------------------------------------------------------------