@yuafox/easepick2-range-plugin 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.md ADDED
@@ -0,0 +1,5 @@
1
+ # Software License Agreement
2
+
3
+ Licensed under the terms of [GNU General Public License Version 2 or later](http://www.gnu.org/licenses/gpl.html).
4
+
5
+ Copyright © 2021-2022, [Rinat G.](https://github.com/wakirin)
package/README.md ADDED
@@ -0,0 +1,38 @@
1
+ # @easepick/range-plugin
2
+
3
+ [![npm version](https://badge.fury.io/js/@easepick%2Frange-plugin.svg)](https://www.npmjs.com/package/@easepick/range-plugin)
4
+
5
+ > This package does not need to be installed if you are using [@easepick/bundle](https://easepick.com/packages/bundle).
6
+
7
+ Adds the ability to select a range of dates.
8
+
9
+
10
+ ## Documentation
11
+
12
+ [https://easepick.com/packages/range-plugin](https://easepick.com/packages/range-plugin)
13
+
14
+
15
+ ## Options
16
+
17
+ | Name | Type | Default | Description
18
+ | --- | :---: | :---: | ---
19
+ | elementEnd | HTMLElement <br/> string | null | Bind the datepicker to a element for end date.
20
+ | startDate | Date <br/> string <br/> number | null | Preselect start date. <br/> Date Object or Unix Timestamp (with milliseconds) or String (must be equal to option format).
21
+ | endDate | Date <br/> string <br/> number | null | Preselect end date. <br/> Date Object or Unix Timestamp (with milliseconds) or String (must be equal to option format).
22
+ | repick | boolean | false | If date range is already selected, then user can change only one of start date or end date (depends on clicked field) instead of new date range.
23
+ | strict | boolean | true | Disabling the option allows you to select an incomplete range.
24
+ | delimiter | string | ' - ' | Delimiter between dates.
25
+ | tooltip | boolean | true | Showing tooltip with how much days will be selected.
26
+ | tooltipNumber | function | | Handling the tooltip number.
27
+ | locale | object | { one: 'day', other: 'days' } | Text for the tooltip. <br/> Keys depends on option lang (see [Intl.PluralRules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/PluralRules)).
28
+
29
+
30
+ ## Methods
31
+
32
+ | Name | Description
33
+ | --- | ---
34
+ | setDateRange(start, end) | Set date range. Should be Date Object or Unix Timestamp (with milliseconds) or String (must be equal to option format).
35
+ | setStartDate(date) | Set start of date range. Should be Date Object or Unix Timestamp (with milliseconds) or String (must be equal to option format).
36
+ | setEndDate(date) | Set end of date range. Should be Date Object or Unix Timestamp (with milliseconds) or String (must be equal to option format).
37
+ | getStartDate() | Return current start of date range as [DateTime](https://easepick.com/packages/datetime) Object.
38
+ | getEndDate() | Return current end of date range as [DateTime](https://easepick.com/packages/datetime) Object.
package/dist/index.css ADDED
@@ -0,0 +1 @@
1
+ :host{--color-bg-inrange:#d5dbff;--color-bg-tooltip:#fff;--color-fg-tooltip:#333}.range-plugin-tooltip{background-color:var(--color-bg-tooltip);border-radius:var(--border-radius);box-shadow:0 1px 3px rgba(0,0,0,.25);color:var(--color-fg-tooltip);font-size:12px;margin-top:-4px;padding:4px 8px;pointer-events:none;position:absolute;visibility:hidden;white-space:nowrap;z-index:1}.range-plugin-tooltip:before{border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid rgba(0,0,0,.12);bottom:-5px;content:"";left:calc(50% - 5px);position:absolute}.range-plugin-tooltip:after{border-left:4px solid transparent;border-right:4px solid transparent;border-top:4px solid var(--color-bg-tooltip);bottom:-4px;content:"";left:calc(50% - 4px);position:absolute}.container.range-plugin .calendar>.days-grid>.day{position:relative}.container.range-plugin .calendar>.days-grid>.day.in-range:last-of-type{border-bottom-right-radius:var(--border-radius);border-top-right-radius:var(--border-radius)}.container.range-plugin .calendar>.days-grid>.day.in-range{background-color:var(--color-bg-inrange);border-radius:0}.container.range-plugin .calendar>.days-grid>.day.end,.container.range-plugin .calendar>.days-grid>.day.start{background-color:var(--color-fg-primary);color:var(--color-fg-selected)}.container.range-plugin .calendar>.days-grid>.day.start{border-bottom-right-radius:0;border-top-right-radius:0}.container.range-plugin .calendar>.days-grid>.day.start:after{border:8px solid transparent;border-left:8px solid var(--color-fg-primary);content:"";pointer-events:none;position:absolute;right:-14px;z-index:1}.container.range-plugin .calendar>.days-grid>.day.start.flipped{border-bottom-left-radius:0;border-bottom-right-radius:var(--border-radius);border-top-left-radius:0;border-top-right-radius:var(--border-radius)}.container.range-plugin .calendar>.days-grid>.day.start.flipped:after{border-left-color:transparent;border-right-color:var(--color-fg-primary);left:-14px;right:auto}.container.range-plugin .calendar>.days-grid>.day.end{border-bottom-left-radius:0;border-top-left-radius:0}.container.range-plugin .calendar>.days-grid>.day.end:after{border:8px solid transparent;border-right:8px solid var(--color-fg-primary);content:"";left:-14px;pointer-events:none;position:absolute;z-index:1}.container.range-plugin .calendar>.days-grid>.day.end.flipped{border-bottom-left-radius:var(--border-radius);border-bottom-right-radius:0;border-top-left-radius:var(--border-radius);border-top-right-radius:0}.container.range-plugin .calendar>.days-grid>.day.end.flipped:after{border-left-color:var(--color-fg-primary);border-right-color:transparent;left:auto;right:-14px}.container.range-plugin .calendar>.days-grid>.day.start.end{border-radius:var(--border-radius)}.container.range-plugin .calendar>.days-grid>.day.start.end:after{content:none}.container.range-plugin .calendar>.days-grid>div:not(.day)+.day.in-range{border-bottom-left-radius:var(--border-radius);border-top-left-radius:var(--border-radius)}.container.range-plugin .calendar>.days-grid>div:nth-child(7n).in-range{border-bottom-right-radius:var(--border-radius);border-top-right-radius:var(--border-radius)}.container.range-plugin .calendar>.days-grid>div:nth-child(7n+1).in-range{border-bottom-left-radius:var(--border-radius);border-top-left-radius:var(--border-radius)}.container.range-plugin .calendar>.months-grid>.month.in-range,.container.range-plugin .calendar>.years-grid>.year.in-range{background-color:var(--color-bg-inrange);border-radius:0}.container.range-plugin .calendar>.months-grid>.month.end,.container.range-plugin .calendar>.months-grid>.month.start,.container.range-plugin .calendar>.years-grid>.year.end,.container.range-plugin .calendar>.years-grid>.year.start{background-color:var(--color-fg-primary);color:var(--color-fg-selected)}.container.range-plugin .calendar>.months-grid>.month.start,.container.range-plugin .calendar>.years-grid>.year.start{border-bottom-right-radius:0;border-top-right-radius:0}.container.range-plugin .calendar>.months-grid>.month.end,.container.range-plugin .calendar>.years-grid>.year.end{border-bottom-left-radius:0;border-top-left-radius:0}.container.range-plugin .calendar>.months-grid>.month.start.end,.container.range-plugin .calendar>.years-grid>.year.start.end{border-radius:var(--border-radius)}
@@ -0,0 +1,145 @@
1
+ import { BasePlugin, IPlugin } from '@yuafox/easepick2-base-plugin';
2
+ import { IRangeConfig } from './interface';
3
+ import './index.scss';
4
+ export declare class RangePlugin extends BasePlugin implements IPlugin {
5
+ tooltipElement: HTMLElement;
6
+ triggerElement: HTMLElement;
7
+ binds: {
8
+ setStartDate: any;
9
+ setEndDate: any;
10
+ setDateRange: any;
11
+ getStartDate: any;
12
+ getEndDate: any;
13
+ onView: any;
14
+ onShow: any;
15
+ onMouseEnter: any;
16
+ onMouseLeave: any;
17
+ onClickCalendarDay: any;
18
+ onClickCalendarMonth: any;
19
+ onClickCalendarYear: any;
20
+ onClickApplyButton: any;
21
+ parseValues: any;
22
+ updateValues: any;
23
+ clear: any;
24
+ };
25
+ options: IRangeConfig;
26
+ /**
27
+ * Returns plugin name
28
+ *
29
+ * @returns String
30
+ */
31
+ getName(): string;
32
+ /**
33
+ * - Called automatically via BasePlugin.attach() -
34
+ * The function execute on initialize the picker
35
+ */
36
+ onAttach(): void;
37
+ /**
38
+ * - Called automatically via BasePlugin.detach() -
39
+ */
40
+ onDetach(): void;
41
+ /**
42
+ * Parse `startDate`, `endDate` options or value of input elements
43
+ */
44
+ private parseValues;
45
+ /**
46
+ * Update value of input element
47
+ */
48
+ private updateValues;
49
+ /**
50
+ * Clear selection
51
+ */
52
+ private clear;
53
+ /**
54
+ * Function `show` event
55
+ *
56
+ * @param event
57
+ */
58
+ private onShow;
59
+ /**
60
+ * Function `view` event
61
+ * Adds HTML layout of current plugin to the picker layout
62
+ *
63
+ * @param event
64
+ */
65
+ private onView;
66
+ /**
67
+ * Function for documentClick option
68
+ * Allows the picker to close when the user clicks outside
69
+ *
70
+ * @param e
71
+ */
72
+ private hidePicker;
73
+ /**
74
+ * Set startDate programmatically
75
+ *
76
+ * @param date
77
+ */
78
+ private setStartDate;
79
+ /**
80
+ * Set endDate programmatically
81
+ *
82
+ * @param date
83
+ */
84
+ private setEndDate;
85
+ /**
86
+ * Set date range programmatically
87
+ *
88
+ * @param start
89
+ * @param end
90
+ */
91
+ private setDateRange;
92
+ /**
93
+ *
94
+ * @returns DateTime
95
+ */
96
+ private getStartDate;
97
+ /**
98
+ *
99
+ * @returns
100
+ */
101
+ private getEndDate;
102
+ /**
103
+ * Handle `mouseenter` event
104
+ *
105
+ * @param event
106
+ */
107
+ private onMouseEnter;
108
+ /**
109
+ * Handle `mouseleave` event
110
+ *
111
+ * @param event
112
+ */
113
+ private onMouseLeave;
114
+ private onClickCalendarDay;
115
+ private onClickCalendarMonth;
116
+ private onClickCalendarYear;
117
+ private handleRangeClick;
118
+ private onClickApplyButton;
119
+ /**
120
+ * Displays tooltip of selected days
121
+ *
122
+ * @param element
123
+ * @param text
124
+ */
125
+ private showTooltip;
126
+ /**
127
+ * Hide tooltip
128
+ */
129
+ private hideTooltip;
130
+ /**
131
+ * Determines if the locale option contains all required plurals
132
+ */
133
+ private checkIntlPluralLocales;
134
+ /**
135
+ * Handle `repick` option
136
+ */
137
+ private initializeRepick;
138
+ /**
139
+ * Determines if the element is the picker container
140
+ *
141
+ * @param element
142
+ * @returns Boolean
143
+ */
144
+ private isContainer;
145
+ }
@@ -0,0 +1 @@
1
+ import{DateTime as t}from"@yuafox/easepick2-datetime";import{BasePlugin as e}from"@yuafox/easepick2-base-plugin";class i extends e{tooltipElement;triggerElement;binds={setStartDate:this.setStartDate.bind(this),setEndDate:this.setEndDate.bind(this),setDateRange:this.setDateRange.bind(this),getStartDate:this.getStartDate.bind(this),getEndDate:this.getEndDate.bind(this),onView:this.onView.bind(this),onShow:this.onShow.bind(this),onMouseEnter:this.onMouseEnter.bind(this),onMouseLeave:this.onMouseLeave.bind(this),onClickCalendarDay:this.onClickCalendarDay.bind(this),onClickCalendarMonth:this.onClickCalendarMonth.bind(this),onClickCalendarYear:this.onClickCalendarYear.bind(this),onClickApplyButton:this.onClickApplyButton.bind(this),parseValues:this.parseValues.bind(this),updateValues:this.updateValues.bind(this),clear:this.clear.bind(this)};options={elementEnd:null,startDate:null,endDate:null,repick:!1,strict:!0,delimiter:" - ",tooltip:!0,tooltipNumber:t=>t,locale:{zero:"",one:"day",two:"",few:"",many:"",other:"days"},documentClick:this.hidePicker.bind(this)};getName(){return"RangePlugin"}onAttach(){this.binds._setStartDate=this.picker.setStartDate,this.binds._setEndDate=this.picker.setEndDate,this.binds._setDateRange=this.picker.setDateRange,this.binds._getStartDate=this.picker.getStartDate,this.binds._getEndDate=this.picker.getEndDate,this.binds._parseValues=this.picker.parseValues,this.binds._updateValues=this.picker.updateValues,this.binds._clear=this.picker.clear,this.binds._onClickCalendarDay=this.picker.onClickCalendarDay,this.binds._onClickApplyButton=this.picker.onClickApplyButton,this.binds._onClickCalendarMonth=this.picker.onClickCalendarMonth,this.binds._onClickCalendarYear=this.picker.onClickCalendarYear,Object.defineProperties(this.picker,{setStartDate:{configurable:!0,value:this.binds.setStartDate},setEndDate:{configurable:!0,value:this.binds.setEndDate},setDateRange:{configurable:!0,value:this.binds.setDateRange},getStartDate:{configurable:!0,value:this.binds.getStartDate},getEndDate:{configurable:!0,value:this.binds.getEndDate},parseValues:{configurable:!0,value:this.binds.parseValues},updateValues:{configurable:!0,value:this.binds.updateValues},clear:{configurable:!0,value:this.binds.clear},onClickCalendarDay:{configurable:!0,value:this.binds.onClickCalendarDay},onClickCalendarMonth:{configurable:!0,value:this.binds.onClickCalendarMonth},onClickCalendarYear:{configurable:!0,value:this.binds.onClickCalendarYear},onClickApplyButton:{configurable:!0,value:this.binds.onClickApplyButton}}),this.options.elementEnd&&(this.options.elementEnd instanceof HTMLElement||(this.options.elementEnd=this.picker.options.doc.querySelector(this.options.elementEnd)),this.options.elementEnd instanceof HTMLInputElement&&(this.options.elementEnd.readOnly=this.picker.options.readonly),"function"==typeof this.picker.options.documentClick&&(document.removeEventListener("click",this.picker.options.documentClick,!0),"function"==typeof this.options.documentClick&&document.addEventListener("click",this.options.documentClick,!0)),this.options.elementEnd.addEventListener("click",this.picker.show.bind(this.picker))),this.options.repick=this.options.repick&&this.options.elementEnd instanceof HTMLElement,this.picker.options.date=null,this.picker.on("view",this.binds.onView),this.picker.on("show",this.binds.onShow),this.picker.on("mouseenter",this.binds.onMouseEnter,!0),this.picker.on("mouseleave",this.binds.onMouseLeave,!0),this.checkIntlPluralLocales()}onDetach(){Object.defineProperties(this.picker,{setStartDate:{configurable:!0,value:this.binds._setStartDate},setEndDate:{configurable:!0,value:this.binds._setEndDate},setDateRange:{configurable:!0,value:this.binds._setDateRange},getStartDate:{configurable:!0,value:this.binds._getStartDate},getEndDate:{configurable:!0,value:this.binds._getEndDate},parseValues:{configurable:!0,value:this.binds._parseValues},updateValues:{configurable:!0,value:this.binds._updateValues},clear:{configurable:!0,value:this.binds._clear},onClickCalendarDay:{configurable:!0,value:this.binds._onClickCalendarDay},onClickCalendarMonth:{configurable:!0,value:this.binds._onClickCalendarMonth},onClickCalendarYear:{configurable:!0,value:this.binds._onClickCalendarYear},onClickApplyButton:{configurable:!0,value:this.binds._onClickApplyButton}}),this.picker.off("view",this.binds.onView),this.picker.off("show",this.binds.onShow),this.picker.off("mouseenter",this.binds.onMouseEnter,!0),this.picker.off("mouseleave",this.binds.onMouseLeave,!0)}parseValues(){if(this.options.startDate||this.options.endDate)this.options.strict?this.options.startDate&&this.options.endDate?this.setDateRange(this.options.startDate,this.options.endDate):(this.options.startDate=null,this.options.endDate=null):(this.options.startDate&&this.setStartDate(this.options.startDate),this.options.endDate&&this.setEndDate(this.options.endDate));else if(this.options.elementEnd)this.options.strict?this.picker.options.element instanceof HTMLInputElement&&this.picker.options.element.value.length&&this.options.elementEnd instanceof HTMLInputElement&&this.options.elementEnd.value.length&&this.setDateRange(this.picker.options.element.value,this.options.elementEnd.value):(this.picker.options.element instanceof HTMLInputElement&&this.picker.options.element.value.length&&this.setStartDate(this.picker.options.element.value),this.options.elementEnd instanceof HTMLInputElement&&this.options.elementEnd.value.length&&this.setEndDate(this.options.elementEnd.value));else if(this.picker.options.element instanceof HTMLInputElement&&this.picker.options.element.value.length){const[t,e]=this.picker.options.element.value.split(this.options.delimiter);this.options.strict?t&&e&&this.setDateRange(t,e):(t&&this.setStartDate(t),e&&this.setEndDate(e))}}updateValues(){const t=this.picker.options.element,e=this.options.elementEnd,i=this.picker.getStartDate(),s=this.picker.getEndDate(),n=i instanceof Date?i.format(this.picker.options.format,this.picker.options.lang):"",a=s instanceof Date?s.format(this.picker.options.format,this.picker.options.lang):"";if(e)t instanceof HTMLInputElement?t.value=n:t instanceof HTMLElement&&(t.innerText=n),e instanceof HTMLInputElement?e.value=a:e instanceof HTMLElement&&(e.innerText=a);else{const e=`${n}${n||a?this.options.delimiter:""}${a}`;t instanceof HTMLInputElement?t.value=e:t instanceof HTMLElement&&(t.innerText=e)}}clear(){this.options.startDate=null,this.options.endDate=null,this.picker.datePicked.length=0,this.updateValues(),this.picker.renderAll(),this.picker.trigger("clear")}onShow(t){const{target:e}=t.detail;this.triggerElement=e,this.picker.options.scrollToDate&&this.getStartDate()instanceof Date&&this.picker.gotoDate(this.getStartDate()),this.initializeRepick()}onView(e){const{view:i,target:s}=e.detail;if("Main"===i&&(this.tooltipElement=document.createElement("span"),this.tooltipElement.className="range-plugin-tooltip",s.appendChild(this.tooltipElement)),"CalendarDay"===i){const e=new t(s.dataset.time),i=this.picker.datePicked,n=i.length?this.picker.datePicked[0]:this.getStartDate(),a=i.length?this.picker.datePicked[1]:this.getEndDate();n&&n.isSame(e,"day")&&s.classList.add("start"),n&&a&&(a.isSame(e,"day")&&s.classList.add("end"),e.isBetween(n,a)&&s.classList.add("in-range"))}if("CalendarMonth"===i){const e=new t(s.dataset.time),i=this.picker.datePicked,n=i.length?this.picker.datePicked[0]:this.getStartDate(),a=1===i.length?null:i.length>=2?this.picker.datePicked[1]:this.getEndDate();if(n&&n.isSame(e,"month")&&(s.classList.add("start"),s.classList.add("selected")),n&&a){a.isSame(e,"month")&&(s.classList.add("end"),s.classList.add("selected"));const i=new t(new Date(n.getFullYear(),n.getMonth(),1)),l=new t(new Date(a.getFullYear(),a.getMonth(),1));e.getTime()>i.getTime()&&e.getTime()<l.getTime()&&s.classList.add("in-range")}}if("CalendarYear"===i){const e=new t(s.dataset.time),i=this.picker.datePicked,n=i.length?this.picker.datePicked[0]:this.getStartDate(),a=1===i.length?null:i.length>=2?this.picker.datePicked[1]:this.getEndDate();n&&e.getFullYear()===n.getFullYear()&&(s.classList.add("start"),s.classList.add("selected")),n&&a&&(e.getFullYear()===a.getFullYear()&&(s.classList.add("end"),s.classList.add("selected")),e.getFullYear()>n.getFullYear()&&e.getFullYear()<a.getFullYear()&&s.classList.add("in-range"))}if("Footer"===i){const t=1===this.picker.datePicked.length&&!this.options.strict||2===this.picker.datePicked.length;s.querySelector(".apply-button").disabled=!t}}hidePicker(t){let e=t.target,i=null;e.shadowRoot&&(e=t.composedPath()[0],i=e.getRootNode().host),this.picker.isShown()&&i!==this.picker.ui.wrapper&&e!==this.picker.options.element&&e!==this.options.elementEnd&&this.picker.hide()}setStartDate(e){const i=new t(e,this.picker.options.format);this.options.startDate=i?i.clone():null,this.updateValues(),this.picker.renderAll()}setEndDate(e){const i=new t(e,this.picker.options.format);this.options.endDate=i?i.clone():null,this.updateValues(),this.picker.renderAll()}setDateRange(e,i){const s=new t(e,this.picker.options.format),n=new t(i,this.picker.options.format);this.options.startDate=s?s.clone():null,this.options.endDate=n?n.clone():null,this.updateValues(),this.picker.renderAll()}getStartDate(){return this.options.startDate instanceof Date?this.options.startDate.clone():null}getEndDate(){return this.options.endDate instanceof Date?this.options.endDate.clone():null}onMouseEnter(e){const i=e.target;if(i instanceof HTMLElement){this.isContainer(i)&&this.initializeRepick();const e=i.closest(".unit");if(!(e instanceof HTMLElement))return;if(this.picker.isCalendarDay(e)){if(1!==this.picker.datePicked.length)return;let i=this.picker.datePicked[0].clone(),s=new t(e.dataset.time),n=!1;if(i.isAfter(s,"day")){const t=i.clone();i=s.clone(),s=t.clone(),n=!0}if([...this.picker.ui.container.querySelectorAll(".day")].forEach((a=>{const l=new t(a.dataset.time),o=this.picker.Calendar.getCalendarDayView(l);l.isBetween(i,s)&&o.classList.add("in-range"),l.isSame(this.picker.datePicked[0],"day")&&(o.classList.add("start"),o.classList.toggle("flipped",n)),a===e&&(o.classList.add("end"),o.classList.toggle("flipped",n)),a.className=o.className})),this.options.tooltip){const t=this.options.tooltipNumber(s.diff(i,"day")+1);if(t>0){const i=new Intl.PluralRules(this.picker.options.lang).select(t),s=`${t} ${this.options.locale[i]}`;this.showTooltip(e,s)}else this.hideTooltip()}}}}onMouseLeave(t){if(this.isContainer(t.target)&&this.options.repick){const t=this.getStartDate(),e=this.getEndDate();t&&e&&(this.picker.datePicked.length=0,this.picker.renderAll())}}onClickCalendarDay(e){if(this.picker.isCalendarDay(e)){2===this.picker.datePicked.length&&(this.picker.datePicked.length=0);const i=new t(e.dataset.time);if(this.picker.datePicked[this.picker.datePicked.length]=i,2===this.picker.datePicked.length&&this.picker.datePicked[0].isAfter(this.picker.datePicked[1])){const t=this.picker.datePicked[1].clone();this.picker.datePicked[1]=this.picker.datePicked[0].clone(),this.picker.datePicked[0]=t.clone()}1!==this.picker.datePicked.length&&this.picker.options.autoApply||this.picker.trigger("preselect",{start:this.picker.datePicked[0]instanceof Date?this.picker.datePicked[0].clone():null,end:this.picker.datePicked[1]instanceof Date?this.picker.datePicked[1].clone():null}),1===this.picker.datePicked.length&&(!this.options.strict&&this.picker.options.autoApply&&(this.picker.options.element===this.triggerElement&&this.setStartDate(this.picker.datePicked[0]),this.options.elementEnd===this.triggerElement&&this.setEndDate(this.picker.datePicked[0]),this.picker.trigger("select",{start:this.picker.getStartDate(),end:this.picker.getEndDate()})),this.picker.renderAll()),2===this.picker.datePicked.length&&(this.picker.options.autoApply?(this.setDateRange(this.picker.datePicked[0],this.picker.datePicked[1]),this.picker.trigger("select",{start:this.picker.getStartDate(),end:this.picker.getEndDate()}),this.picker.hide()):(this.hideTooltip(),this.picker.renderAll()))}}onClickCalendarMonth(t){this.picker.isCalendarMonth(t)&&this.handleRangeClick(t,"month")}onClickCalendarYear(t){this.picker.isCalendarYear(t)&&this.handleRangeClick(t,"year")}handleRangeClick(e,i){2===this.picker.datePicked.length&&(this.picker.datePicked.length=0);const s=new t(e.dataset.time);if(this.picker.datePicked[this.picker.datePicked.length]=s,2===this.picker.datePicked.length&&this.picker.datePicked[0].isAfter(this.picker.datePicked[1],i)){const t=this.picker.datePicked[1].clone();this.picker.datePicked[1]=this.picker.datePicked[0].clone(),this.picker.datePicked[0]=t.clone()}1!==this.picker.datePicked.length&&this.picker.options.autoApply||this.picker.trigger("preselect",{start:this.picker.datePicked[0]instanceof Date?this.picker.datePicked[0].clone():null,end:this.picker.datePicked[1]instanceof Date?this.picker.datePicked[1].clone():null}),1===this.picker.datePicked.length&&this.picker.renderAll(),2===this.picker.datePicked.length&&(this.picker.options.autoApply?(this.setDateRange(this.picker.datePicked[0],this.picker.datePicked[1]),this.picker.trigger("select",{start:this.picker.getStartDate(),end:this.picker.getEndDate()}),this.picker.hide()):this.picker.renderAll())}onClickApplyButton(t){this.picker.isApplyButton(t)&&(1!==this.picker.datePicked.length||this.options.strict||(this.picker.options.element===this.triggerElement&&(this.options.endDate=null,this.setStartDate(this.picker.datePicked[0])),this.options.elementEnd===this.triggerElement&&(this.options.startDate=null,this.setEndDate(this.picker.datePicked[0]))),2===this.picker.datePicked.length&&this.setDateRange(this.picker.datePicked[0],this.picker.datePicked[1]),this.picker.trigger("select",{start:this.picker.getStartDate(),end:this.picker.getEndDate()}),this.picker.hide())}showTooltip(t,e){this.tooltipElement.style.visibility="visible",this.tooltipElement.innerHTML=e;const i=this.picker.ui.container.getBoundingClientRect(),s=this.tooltipElement.getBoundingClientRect(),n=t.getBoundingClientRect();let a=n.top,l=n.left;a-=i.top,l-=i.left,a-=s.height,l-=s.width/2,l+=n.width/2,this.tooltipElement.style.top=`${a}px`,this.tooltipElement.style.left=`${l}px`}hideTooltip(){this.tooltipElement.style.visibility="hidden"}checkIntlPluralLocales(){if(!this.options.tooltip)return;const t=[...new Set([new Intl.PluralRules(this.picker.options.lang).select(0),new Intl.PluralRules(this.picker.options.lang).select(1),new Intl.PluralRules(this.picker.options.lang).select(2),new Intl.PluralRules(this.picker.options.lang).select(6),new Intl.PluralRules(this.picker.options.lang).select(18)])],e=Object.keys(this.options.locale);t.every((t=>e.includes(t)))||console.warn(`${this.getName()}: provide locales (${t.join(", ")}) for correct tooltip text.`)}initializeRepick(){if(!this.options.repick)return;const t=this.getStartDate(),e=this.getEndDate();e&&this.triggerElement===this.picker.options.element&&(this.picker.datePicked[0]=e),t&&this.triggerElement===this.options.elementEnd&&(this.picker.datePicked[0]=t)}isContainer(t){return t===this.picker.ui.container}}export{i as RangePlugin};
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @license
3
+ * Package: @yuafox/easepick2-range-plugin
4
+ * Version: 2.0.0
5
+ * https://github.com/YuaFox/easepick2
6
+ * Copyright 2026 YuaFox
7
+ *
8
+ * Licensed under the terms of GNU General Public License Version 2 or later. (http://www.gnu.org/licenses/gpl.html)
9
+ */
10
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("@yuafox/easepick2-datetime"),require("@yuafox/easepick2-base-plugin")):"function"==typeof define&&define.amd?define(["exports","@yuafox/easepick2-datetime","@yuafox/easepick2-base-plugin"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).easepick=e.easepick||{},e.easepick,e.easepick)}(this,(function(e,t,i){"use strict";class s extends i.BasePlugin{tooltipElement;triggerElement;binds={setStartDate:this.setStartDate.bind(this),setEndDate:this.setEndDate.bind(this),setDateRange:this.setDateRange.bind(this),getStartDate:this.getStartDate.bind(this),getEndDate:this.getEndDate.bind(this),onView:this.onView.bind(this),onShow:this.onShow.bind(this),onMouseEnter:this.onMouseEnter.bind(this),onMouseLeave:this.onMouseLeave.bind(this),onClickCalendarDay:this.onClickCalendarDay.bind(this),onClickCalendarMonth:this.onClickCalendarMonth.bind(this),onClickCalendarYear:this.onClickCalendarYear.bind(this),onClickApplyButton:this.onClickApplyButton.bind(this),parseValues:this.parseValues.bind(this),updateValues:this.updateValues.bind(this),clear:this.clear.bind(this)};options={elementEnd:null,startDate:null,endDate:null,repick:!1,strict:!0,delimiter:" - ",tooltip:!0,tooltipNumber:e=>e,locale:{zero:"",one:"day",two:"",few:"",many:"",other:"days"},documentClick:this.hidePicker.bind(this)};getName(){return"RangePlugin"}onAttach(){this.binds._setStartDate=this.picker.setStartDate,this.binds._setEndDate=this.picker.setEndDate,this.binds._setDateRange=this.picker.setDateRange,this.binds._getStartDate=this.picker.getStartDate,this.binds._getEndDate=this.picker.getEndDate,this.binds._parseValues=this.picker.parseValues,this.binds._updateValues=this.picker.updateValues,this.binds._clear=this.picker.clear,this.binds._onClickCalendarDay=this.picker.onClickCalendarDay,this.binds._onClickApplyButton=this.picker.onClickApplyButton,this.binds._onClickCalendarMonth=this.picker.onClickCalendarMonth,this.binds._onClickCalendarYear=this.picker.onClickCalendarYear,Object.defineProperties(this.picker,{setStartDate:{configurable:!0,value:this.binds.setStartDate},setEndDate:{configurable:!0,value:this.binds.setEndDate},setDateRange:{configurable:!0,value:this.binds.setDateRange},getStartDate:{configurable:!0,value:this.binds.getStartDate},getEndDate:{configurable:!0,value:this.binds.getEndDate},parseValues:{configurable:!0,value:this.binds.parseValues},updateValues:{configurable:!0,value:this.binds.updateValues},clear:{configurable:!0,value:this.binds.clear},onClickCalendarDay:{configurable:!0,value:this.binds.onClickCalendarDay},onClickCalendarMonth:{configurable:!0,value:this.binds.onClickCalendarMonth},onClickCalendarYear:{configurable:!0,value:this.binds.onClickCalendarYear},onClickApplyButton:{configurable:!0,value:this.binds.onClickApplyButton}}),this.options.elementEnd&&(this.options.elementEnd instanceof HTMLElement||(this.options.elementEnd=this.picker.options.doc.querySelector(this.options.elementEnd)),this.options.elementEnd instanceof HTMLInputElement&&(this.options.elementEnd.readOnly=this.picker.options.readonly),"function"==typeof this.picker.options.documentClick&&(document.removeEventListener("click",this.picker.options.documentClick,!0),"function"==typeof this.options.documentClick&&document.addEventListener("click",this.options.documentClick,!0)),this.options.elementEnd.addEventListener("click",this.picker.show.bind(this.picker))),this.options.repick=this.options.repick&&this.options.elementEnd instanceof HTMLElement,this.picker.options.date=null,this.picker.on("view",this.binds.onView),this.picker.on("show",this.binds.onShow),this.picker.on("mouseenter",this.binds.onMouseEnter,!0),this.picker.on("mouseleave",this.binds.onMouseLeave,!0),this.checkIntlPluralLocales()}onDetach(){Object.defineProperties(this.picker,{setStartDate:{configurable:!0,value:this.binds._setStartDate},setEndDate:{configurable:!0,value:this.binds._setEndDate},setDateRange:{configurable:!0,value:this.binds._setDateRange},getStartDate:{configurable:!0,value:this.binds._getStartDate},getEndDate:{configurable:!0,value:this.binds._getEndDate},parseValues:{configurable:!0,value:this.binds._parseValues},updateValues:{configurable:!0,value:this.binds._updateValues},clear:{configurable:!0,value:this.binds._clear},onClickCalendarDay:{configurable:!0,value:this.binds._onClickCalendarDay},onClickCalendarMonth:{configurable:!0,value:this.binds._onClickCalendarMonth},onClickCalendarYear:{configurable:!0,value:this.binds._onClickCalendarYear},onClickApplyButton:{configurable:!0,value:this.binds._onClickApplyButton}}),this.picker.off("view",this.binds.onView),this.picker.off("show",this.binds.onShow),this.picker.off("mouseenter",this.binds.onMouseEnter,!0),this.picker.off("mouseleave",this.binds.onMouseLeave,!0)}parseValues(){if(this.options.startDate||this.options.endDate)this.options.strict?this.options.startDate&&this.options.endDate?this.setDateRange(this.options.startDate,this.options.endDate):(this.options.startDate=null,this.options.endDate=null):(this.options.startDate&&this.setStartDate(this.options.startDate),this.options.endDate&&this.setEndDate(this.options.endDate));else if(this.options.elementEnd)this.options.strict?this.picker.options.element instanceof HTMLInputElement&&this.picker.options.element.value.length&&this.options.elementEnd instanceof HTMLInputElement&&this.options.elementEnd.value.length&&this.setDateRange(this.picker.options.element.value,this.options.elementEnd.value):(this.picker.options.element instanceof HTMLInputElement&&this.picker.options.element.value.length&&this.setStartDate(this.picker.options.element.value),this.options.elementEnd instanceof HTMLInputElement&&this.options.elementEnd.value.length&&this.setEndDate(this.options.elementEnd.value));else if(this.picker.options.element instanceof HTMLInputElement&&this.picker.options.element.value.length){const[e,t]=this.picker.options.element.value.split(this.options.delimiter);this.options.strict?e&&t&&this.setDateRange(e,t):(e&&this.setStartDate(e),t&&this.setEndDate(t))}}updateValues(){const e=this.picker.options.element,t=this.options.elementEnd,i=this.picker.getStartDate(),s=this.picker.getEndDate(),n=i instanceof Date?i.format(this.picker.options.format,this.picker.options.lang):"",a=s instanceof Date?s.format(this.picker.options.format,this.picker.options.lang):"";if(t)e instanceof HTMLInputElement?e.value=n:e instanceof HTMLElement&&(e.innerText=n),t instanceof HTMLInputElement?t.value=a:t instanceof HTMLElement&&(t.innerText=a);else{const t=`${n}${n||a?this.options.delimiter:""}${a}`;e instanceof HTMLInputElement?e.value=t:e instanceof HTMLElement&&(e.innerText=t)}}clear(){this.options.startDate=null,this.options.endDate=null,this.picker.datePicked.length=0,this.updateValues(),this.picker.renderAll(),this.picker.trigger("clear")}onShow(e){const{target:t}=e.detail;this.triggerElement=t,this.picker.options.scrollToDate&&this.getStartDate()instanceof Date&&this.picker.gotoDate(this.getStartDate()),this.initializeRepick()}onView(e){const{view:i,target:s}=e.detail;if("Main"===i&&(this.tooltipElement=document.createElement("span"),this.tooltipElement.className="range-plugin-tooltip",s.appendChild(this.tooltipElement)),"CalendarDay"===i){const e=new t.DateTime(s.dataset.time),i=this.picker.datePicked,n=i.length?this.picker.datePicked[0]:this.getStartDate(),a=i.length?this.picker.datePicked[1]:this.getEndDate();n&&n.isSame(e,"day")&&s.classList.add("start"),n&&a&&(a.isSame(e,"day")&&s.classList.add("end"),e.isBetween(n,a)&&s.classList.add("in-range"))}if("CalendarMonth"===i){const e=new t.DateTime(s.dataset.time),i=this.picker.datePicked,n=i.length?this.picker.datePicked[0]:this.getStartDate(),a=1===i.length?null:i.length>=2?this.picker.datePicked[1]:this.getEndDate();if(n&&n.isSame(e,"month")&&(s.classList.add("start"),s.classList.add("selected")),n&&a){a.isSame(e,"month")&&(s.classList.add("end"),s.classList.add("selected"));const i=new t.DateTime(new Date(n.getFullYear(),n.getMonth(),1)),l=new t.DateTime(new Date(a.getFullYear(),a.getMonth(),1));e.getTime()>i.getTime()&&e.getTime()<l.getTime()&&s.classList.add("in-range")}}if("CalendarYear"===i){const e=new t.DateTime(s.dataset.time),i=this.picker.datePicked,n=i.length?this.picker.datePicked[0]:this.getStartDate(),a=1===i.length?null:i.length>=2?this.picker.datePicked[1]:this.getEndDate();n&&e.getFullYear()===n.getFullYear()&&(s.classList.add("start"),s.classList.add("selected")),n&&a&&(e.getFullYear()===a.getFullYear()&&(s.classList.add("end"),s.classList.add("selected")),e.getFullYear()>n.getFullYear()&&e.getFullYear()<a.getFullYear()&&s.classList.add("in-range"))}if("Footer"===i){const e=1===this.picker.datePicked.length&&!this.options.strict||2===this.picker.datePicked.length;s.querySelector(".apply-button").disabled=!e}}hidePicker(e){let t=e.target,i=null;t.shadowRoot&&(t=e.composedPath()[0],i=t.getRootNode().host),this.picker.isShown()&&i!==this.picker.ui.wrapper&&t!==this.picker.options.element&&t!==this.options.elementEnd&&this.picker.hide()}setStartDate(e){const i=new t.DateTime(e,this.picker.options.format);this.options.startDate=i?i.clone():null,this.updateValues(),this.picker.renderAll()}setEndDate(e){const i=new t.DateTime(e,this.picker.options.format);this.options.endDate=i?i.clone():null,this.updateValues(),this.picker.renderAll()}setDateRange(e,i){const s=new t.DateTime(e,this.picker.options.format),n=new t.DateTime(i,this.picker.options.format);this.options.startDate=s?s.clone():null,this.options.endDate=n?n.clone():null,this.updateValues(),this.picker.renderAll()}getStartDate(){return this.options.startDate instanceof Date?this.options.startDate.clone():null}getEndDate(){return this.options.endDate instanceof Date?this.options.endDate.clone():null}onMouseEnter(e){const i=e.target;if(i instanceof HTMLElement){this.isContainer(i)&&this.initializeRepick();const e=i.closest(".unit");if(!(e instanceof HTMLElement))return;if(this.picker.isCalendarDay(e)){if(1!==this.picker.datePicked.length)return;let i=this.picker.datePicked[0].clone(),s=new t.DateTime(e.dataset.time),n=!1;if(i.isAfter(s,"day")){const e=i.clone();i=s.clone(),s=e.clone(),n=!0}if([...this.picker.ui.container.querySelectorAll(".day")].forEach((a=>{const l=new t.DateTime(a.dataset.time),o=this.picker.Calendar.getCalendarDayView(l);l.isBetween(i,s)&&o.classList.add("in-range"),l.isSame(this.picker.datePicked[0],"day")&&(o.classList.add("start"),o.classList.toggle("flipped",n)),a===e&&(o.classList.add("end"),o.classList.toggle("flipped",n)),a.className=o.className})),this.options.tooltip){const t=this.options.tooltipNumber(s.diff(i,"day")+1);if(t>0){const i=new Intl.PluralRules(this.picker.options.lang).select(t),s=`${t} ${this.options.locale[i]}`;this.showTooltip(e,s)}else this.hideTooltip()}}}}onMouseLeave(e){if(this.isContainer(e.target)&&this.options.repick){const e=this.getStartDate(),t=this.getEndDate();e&&t&&(this.picker.datePicked.length=0,this.picker.renderAll())}}onClickCalendarDay(e){if(this.picker.isCalendarDay(e)){2===this.picker.datePicked.length&&(this.picker.datePicked.length=0);const i=new t.DateTime(e.dataset.time);if(this.picker.datePicked[this.picker.datePicked.length]=i,2===this.picker.datePicked.length&&this.picker.datePicked[0].isAfter(this.picker.datePicked[1])){const e=this.picker.datePicked[1].clone();this.picker.datePicked[1]=this.picker.datePicked[0].clone(),this.picker.datePicked[0]=e.clone()}1!==this.picker.datePicked.length&&this.picker.options.autoApply||this.picker.trigger("preselect",{start:this.picker.datePicked[0]instanceof Date?this.picker.datePicked[0].clone():null,end:this.picker.datePicked[1]instanceof Date?this.picker.datePicked[1].clone():null}),1===this.picker.datePicked.length&&(!this.options.strict&&this.picker.options.autoApply&&(this.picker.options.element===this.triggerElement&&this.setStartDate(this.picker.datePicked[0]),this.options.elementEnd===this.triggerElement&&this.setEndDate(this.picker.datePicked[0]),this.picker.trigger("select",{start:this.picker.getStartDate(),end:this.picker.getEndDate()})),this.picker.renderAll()),2===this.picker.datePicked.length&&(this.picker.options.autoApply?(this.setDateRange(this.picker.datePicked[0],this.picker.datePicked[1]),this.picker.trigger("select",{start:this.picker.getStartDate(),end:this.picker.getEndDate()}),this.picker.hide()):(this.hideTooltip(),this.picker.renderAll()))}}onClickCalendarMonth(e){this.picker.isCalendarMonth(e)&&this.handleRangeClick(e,"month")}onClickCalendarYear(e){this.picker.isCalendarYear(e)&&this.handleRangeClick(e,"year")}handleRangeClick(e,i){2===this.picker.datePicked.length&&(this.picker.datePicked.length=0);const s=new t.DateTime(e.dataset.time);if(this.picker.datePicked[this.picker.datePicked.length]=s,2===this.picker.datePicked.length&&this.picker.datePicked[0].isAfter(this.picker.datePicked[1],i)){const e=this.picker.datePicked[1].clone();this.picker.datePicked[1]=this.picker.datePicked[0].clone(),this.picker.datePicked[0]=e.clone()}1!==this.picker.datePicked.length&&this.picker.options.autoApply||this.picker.trigger("preselect",{start:this.picker.datePicked[0]instanceof Date?this.picker.datePicked[0].clone():null,end:this.picker.datePicked[1]instanceof Date?this.picker.datePicked[1].clone():null}),1===this.picker.datePicked.length&&this.picker.renderAll(),2===this.picker.datePicked.length&&(this.picker.options.autoApply?(this.setDateRange(this.picker.datePicked[0],this.picker.datePicked[1]),this.picker.trigger("select",{start:this.picker.getStartDate(),end:this.picker.getEndDate()}),this.picker.hide()):this.picker.renderAll())}onClickApplyButton(e){this.picker.isApplyButton(e)&&(1!==this.picker.datePicked.length||this.options.strict||(this.picker.options.element===this.triggerElement&&(this.options.endDate=null,this.setStartDate(this.picker.datePicked[0])),this.options.elementEnd===this.triggerElement&&(this.options.startDate=null,this.setEndDate(this.picker.datePicked[0]))),2===this.picker.datePicked.length&&this.setDateRange(this.picker.datePicked[0],this.picker.datePicked[1]),this.picker.trigger("select",{start:this.picker.getStartDate(),end:this.picker.getEndDate()}),this.picker.hide())}showTooltip(e,t){this.tooltipElement.style.visibility="visible",this.tooltipElement.innerHTML=t;const i=this.picker.ui.container.getBoundingClientRect(),s=this.tooltipElement.getBoundingClientRect(),n=e.getBoundingClientRect();let a=n.top,l=n.left;a-=i.top,l-=i.left,a-=s.height,l-=s.width/2,l+=n.width/2,this.tooltipElement.style.top=`${a}px`,this.tooltipElement.style.left=`${l}px`}hideTooltip(){this.tooltipElement.style.visibility="hidden"}checkIntlPluralLocales(){if(!this.options.tooltip)return;const e=[...new Set([new Intl.PluralRules(this.picker.options.lang).select(0),new Intl.PluralRules(this.picker.options.lang).select(1),new Intl.PluralRules(this.picker.options.lang).select(2),new Intl.PluralRules(this.picker.options.lang).select(6),new Intl.PluralRules(this.picker.options.lang).select(18)])],t=Object.keys(this.options.locale);e.every((e=>t.includes(e)))||console.warn(`${this.getName()}: provide locales (${e.join(", ")}) for correct tooltip text.`)}initializeRepick(){if(!this.options.repick)return;const e=this.getStartDate(),t=this.getEndDate();t&&this.triggerElement===this.picker.options.element&&(this.picker.datePicked[0]=t),e&&this.triggerElement===this.options.elementEnd&&(this.picker.datePicked[0]=e)}isContainer(e){return e===this.picker.ui.container}}e.RangePlugin=s,Object.defineProperty(e,"__esModule",{value:!0})}));
@@ -0,0 +1,35 @@
1
+ import { DateTime } from '@yuafox/easepick2-datetime';
2
+ import { IBaseConfig } from '@yuafox/easepick2-base-plugin';
3
+ export interface IRangeConfig extends IBaseConfig {
4
+ elementEnd?: HTMLElement | string;
5
+ startDate?: DateTime;
6
+ endDate?: DateTime;
7
+ repick?: boolean;
8
+ strict?: boolean;
9
+ delimiter?: string;
10
+ tooltip?: boolean;
11
+ tooltipNumber?: (num: number) => number;
12
+ locale?: {
13
+ zero?: string;
14
+ one?: string;
15
+ two?: string;
16
+ few?: string;
17
+ many?: string;
18
+ other?: string;
19
+ };
20
+ documentClick?: boolean | (() => void);
21
+ }
22
+ declare module '@yuafox/easepick2-core' {
23
+ interface Core {
24
+ setStartDate(date: Date | string | number): void;
25
+ setEndDate(date: Date | string | number): void;
26
+ setDateRange(start: Date | string | number, end: Date | string | number): void;
27
+ getStartDate(): DateTime;
28
+ getEndDate(): DateTime;
29
+ }
30
+ }
31
+ declare module '@yuafox/easepick2-core/dist/types' {
32
+ interface IPickerConfig {
33
+ RangePlugin?: IRangeConfig;
34
+ }
35
+ }
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@yuafox/easepick2-range-plugin",
3
+ "description": "Range plugin for easepick2.",
4
+ "version": "2.0.0",
5
+ "main": "dist/index.umd.js",
6
+ "module": "dist/index.esm.js",
7
+ "types": "dist/index.d.ts",
8
+ "dependencies": {
9
+ "@yuafox/easepick2-base-plugin": "^2.0.0"
10
+ },
11
+ "author": {
12
+ "name": "YuaFox"
13
+ },
14
+ "license": "GPL-2.0-or-later",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/YuaFox/easepick2.git",
18
+ "directory": "packages/range-plugin"
19
+ },
20
+ "homepage": "https://github.com/YuaFox/easepick2",
21
+ "bugs": {
22
+ "url": "https://github.com/YuaFox/easepick2/issues"
23
+ },
24
+ "files": [
25
+ "dist"
26
+ ]
27
+ }