@gez/date-time-kit 1.1.4 → 2.0.0-alpha.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.
Files changed (77) hide show
  1. package/dist/assets/arrow-down.svg +1 -0
  2. package/dist/assets/arrow-left-double.svg +1 -0
  3. package/dist/assets/arrow-left.svg +1 -0
  4. package/dist/assets/arrow-right-double.svg +1 -0
  5. package/dist/assets/arrow-right.svg +1 -0
  6. package/dist/assets/back-arrow.svg +1 -0
  7. package/dist/assets/time.svg +1 -0
  8. package/dist/components/calendar/index.css +108 -0
  9. package/dist/components/calendar/index.d.ts +84 -0
  10. package/dist/components/calendar/index.mjs +238 -0
  11. package/dist/components/hhmmss-ms-list-grp/index.css +60 -0
  12. package/dist/components/hhmmss-ms-list-grp/index.d.ts +54 -0
  13. package/dist/components/hhmmss-ms-list-grp/index.mjs +226 -0
  14. package/dist/components/i18n/index.d.ts +13 -0
  15. package/dist/components/i18n/index.mjs +42 -0
  16. package/dist/components/num-list/index.css +35 -0
  17. package/dist/components/num-list/index.d.ts +68 -0
  18. package/dist/components/num-list/index.mjs +259 -0
  19. package/dist/components/period-selector/date-nav.css +92 -0
  20. package/dist/components/period-selector/date-nav.d.ts +64 -0
  21. package/dist/components/period-selector/date-nav.mjs +161 -0
  22. package/dist/components/period-selector/index.css +152 -0
  23. package/dist/components/period-selector/index.d.ts +68 -0
  24. package/dist/components/period-selector/index.mjs +312 -0
  25. package/dist/components/popover/index.d.ts +34 -0
  26. package/dist/components/popover/index.mjs +104 -0
  27. package/dist/components/quick-selector/index.css +167 -0
  28. package/dist/components/quick-selector/index.d.ts +74 -0
  29. package/dist/components/quick-selector/index.mjs +347 -0
  30. package/dist/components/web-component-base/index.css +9 -0
  31. package/dist/components/web-component-base/index.d.ts +46 -0
  32. package/dist/components/web-component-base/index.mjs +118 -0
  33. package/dist/components/web-component-base/scrollbar.css +25 -0
  34. package/dist/components/yyyymmdd-list-grp/index.css +32 -0
  35. package/dist/components/yyyymmdd-list-grp/index.d.ts +52 -0
  36. package/dist/components/yyyymmdd-list-grp/index.mjs +181 -0
  37. package/dist/i18n.d.ts +36 -0
  38. package/dist/i18n.mjs +368 -0
  39. package/dist/index.d.ts +7 -0
  40. package/dist/index.mjs +15 -0
  41. package/dist/utils.d.ts +12 -0
  42. package/dist/utils.mjs +21 -0
  43. package/package.json +37 -63
  44. package/src/assets/arrow-down.svg +1 -0
  45. package/src/assets/arrow-left-double.svg +1 -0
  46. package/src/assets/arrow-left.svg +1 -0
  47. package/src/assets/arrow-right-double.svg +1 -0
  48. package/src/assets/arrow-right.svg +1 -0
  49. package/src/assets/back-arrow.svg +1 -0
  50. package/src/assets/time.svg +1 -0
  51. package/src/components/calendar/index.scss +128 -0
  52. package/src/components/calendar/index.ts +453 -0
  53. package/src/components/hhmmss-ms-list-grp/index.scss +61 -0
  54. package/src/components/hhmmss-ms-list-grp/index.ts +387 -0
  55. package/src/components/i18n/index.ts +48 -0
  56. package/src/components/num-list/index.scss +38 -0
  57. package/src/components/num-list/index.ts +357 -0
  58. package/src/components/period-selector/date-nav.scss +108 -0
  59. package/src/components/period-selector/date-nav.ts +322 -0
  60. package/src/components/period-selector/index.scss +160 -0
  61. package/src/components/period-selector/index.ts +552 -0
  62. package/src/components/popover/index.ts +127 -0
  63. package/src/components/quick-selector/index.scss +183 -0
  64. package/src/components/quick-selector/index.ts +611 -0
  65. package/src/components/web-component-base/index.scss +11 -0
  66. package/src/components/web-component-base/index.ts +235 -0
  67. package/src/components/web-component-base/scrollbar.scss +30 -0
  68. package/src/components/yyyymmdd-list-grp/index.scss +33 -0
  69. package/src/components/yyyymmdd-list-grp/index.ts +257 -0
  70. package/src/i18n.ts +415 -0
  71. package/src/index.ts +12 -0
  72. package/src/utils.ts +36 -0
  73. package/README.md +0 -152
  74. package/dist/index.css +0 -1
  75. package/dist/index.html +0 -85
  76. package/dist/index.js +0 -145
  77. package/type.d.ts +0 -164
@@ -0,0 +1,552 @@
1
+ import { closestByEvent, css, debounce, html } from '../../utils';
2
+ import { type BaseAttrs, UiBase } from '../web-component-base';
3
+ // import styleStr from './index.scss?inline';
4
+ const styleStr = css`
5
+ :host {
6
+ display: flex;
7
+ flex-direction: column;
8
+ gap: 15px;
9
+ }
10
+
11
+ .date-echo {
12
+ display: flex;
13
+ gap: 5px;
14
+ align-items: center;
15
+ }
16
+
17
+ .start-date-echo-wrapper,
18
+ .end-date-echo-wrapper {
19
+ width: 100%;
20
+ flex: 1;
21
+ display: flex;
22
+ flex-direction: column;
23
+ gap: 2px;
24
+ border-radius: 6px;
25
+ border: 1px solid rgba(0, 0, 0, 0.1490196078);
26
+ padding: 4px;
27
+ }
28
+ .start-date-echo-wrapper.active,
29
+ .end-date-echo-wrapper.active {
30
+ border-color: #333;
31
+ }
32
+
33
+ .date-echo .label {
34
+ font-size: 14px;
35
+ line-height: 1;
36
+ }
37
+
38
+ .start-date-echo, .end-date-echo {
39
+ font-size: 16px;
40
+ line-height: 1;
41
+ font-weight: bold;
42
+ }
43
+
44
+ .dividing-line {
45
+ display: block;
46
+ height: 1px;
47
+ width: 20px;
48
+ background-color: #eee;
49
+ }
50
+
51
+ dt-date-nav::part(list-grp) {
52
+ height: 254px;
53
+ margin-top: 15px;
54
+ }
55
+
56
+ dt-calendar-base.hide {
57
+ display: none;
58
+ }
59
+
60
+ .calendars {
61
+ display: flex;
62
+ gap: 20px;
63
+ }
64
+
65
+ .wrapper {
66
+ flex: 1;
67
+ height: 100%;
68
+ display: flex;
69
+ flex-direction: column;
70
+ gap: 15px;
71
+ }
72
+
73
+ dt-popover {
74
+ position: relative;
75
+ }
76
+
77
+ [open] .time-echo-wrapper {
78
+ border-color: #18181B;
79
+ }
80
+
81
+ .time-echo-wrapper {
82
+ width: 100%;
83
+ padding: 4px;
84
+ display: flex;
85
+ gap: 5px;
86
+ border-radius: 4px;
87
+ min-height: 30px;
88
+ border: 1px solid rgba(0, 0, 0, 0.0666666667);
89
+ box-sizing: border-box;
90
+ align-items: center;
91
+ }
92
+
93
+ .time-selector {
94
+ position: absolute;
95
+ width: 100%;
96
+ height: 461px;
97
+ box-sizing: border-box;
98
+ background-color: #fff;
99
+ display: flex;
100
+ flex-direction: column;
101
+ gap: 15px;
102
+ padding: 15px;
103
+ border-radius: 6px;
104
+ border: 1px solid #eee;
105
+ box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
106
+ }
107
+ .time-selector .title {
108
+ font-size: 16px;
109
+ margin: 0;
110
+ line-height: 1;
111
+ }
112
+
113
+ dt-hhmmss-ms-list-grp::part(list-container) {
114
+ gap: 2px;
115
+ }
116
+ dt-hhmmss-ms-list-grp::part(list) {
117
+ scroll-behavior: smooth;
118
+ }
119
+ dt-hhmmss-ms-list-grp::part(item) {
120
+ font-size: 14px;
121
+ line-height: 17px;
122
+ }
123
+
124
+ #time-selector-done-btn {
125
+ border: none;
126
+ min-height: 30px;
127
+ border-radius: 6px;
128
+ padding: 5px 10px;
129
+ font-size: 14px;
130
+ background-color: #18181B;
131
+ color: #fff;
132
+ }
133
+
134
+ .time-icon {
135
+ display: inline-block;
136
+ width: 20px;
137
+ height: 20px;
138
+ background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='15' fill='currentColor'%3E%3Cpath d='M7.4335 4.241a.4376.4376 0 0 0-.871.0594v3.783l.0044.0622a.4375.4375 0 0 0 .1921.3029L8.9242 9.877l.0566.0317a.4376.4376 0 0 0 .5495-.1559l.0317-.0566a.4376.4376 0 0 0-.1559-.5495L7.4375 7.8471V4.3004l-.004-.0593ZM7 1.6667c-3.2217 0-5.8333 2.6116-5.8333 5.8333 0 3.2217 2.6116 5.8333 5.8333 5.8333 3.2217 0 5.8333-2.6116 5.8333-5.8333 0-3.2217-2.6116-5.8333-5.8333-5.8333Zm0 .814c2.7721 0 5.0194 2.2472 5.0194 5.0193 0 2.7721-2.2473 5.0194-5.0194 5.0194S1.9806 10.2721 1.9806 7.5 4.228 2.4806 7 2.4806Z'/%3E%3C/svg%3E") 50%/20px 20px no-repeat;
139
+ }
140
+
141
+ .time-echo {
142
+ font-size: 14px;
143
+ color: #999;
144
+ line-height: 1;
145
+ }
146
+
147
+ dt-calendar-base {
148
+ height: 254px;
149
+ }
150
+ dt-calendar-base::part(week) {
151
+ font-size: 12px;
152
+ line-height: 14px;
153
+ }
154
+ dt-calendar-base::part(item) {
155
+ font-size: 14px;
156
+ }
157
+ `;
158
+ import { Ele as DateNavEle, type EventMap as DateNavEvent } from './date-nav';
159
+ DateNavEle.define();
160
+ import {
161
+ Ele as CalendarBaseEle,
162
+ type EventMap as CalendarBaseEvent
163
+ } from '../calendar';
164
+ CalendarBaseEle.define();
165
+ import { Ele as HhMmSsMsListGrpEle } from '../hhmmss-ms-list-grp';
166
+ HhMmSsMsListGrpEle.define();
167
+ import { Ele as PopoverEle, type EventMap as PopoverEvent } from '../popover';
168
+ PopoverEle.define();
169
+
170
+ export interface Attrs extends BaseAttrs {
171
+ /**
172
+ * The start time of the calendar display range.
173
+ * @type {`string | number`} A value that can be passed to the Date constructor.
174
+ * @default Date.now()
175
+ */
176
+ 'time-start'?: string | number;
177
+ /**
178
+ * The end time of the calendar display range.
179
+ * @type {`string | number`} A value that can be passed to the Date constructor.
180
+ * @default 'time-start'
181
+ */
182
+ 'time-end': string | number;
183
+ /**
184
+ * 选择器的粒度,表示最小可选的时间单位。默认为 millisecond。
185
+ * 例如设置为 'minute',则表示只能选择到分钟,秒和毫秒将被忽略。
186
+ */
187
+ 'min-granularity'?: 'day' | 'hour' | 'minute' | 'second' | 'millisecond';
188
+ }
189
+
190
+ export interface Emits {
191
+ change: {
192
+ oldStartTime: Date;
193
+ oldEndTime: Date;
194
+ newStartTime: Date;
195
+ newEndTime: Date;
196
+ };
197
+ }
198
+
199
+ const diffInMonth = (a: Date, b: Date) => {
200
+ if (a > b) [a, b] = [b, a];
201
+ const aYear = a.getFullYear();
202
+ const aMonth = a.getMonth();
203
+ const bYear = b.getFullYear();
204
+ const bMonth = b.getMonth();
205
+ return bYear * 12 + bMonth - (aYear * 12 + aMonth);
206
+ };
207
+
208
+ /**
209
+ * 时间段选择器(两个日历)
210
+ *
211
+ * 存在一个 timeFormatter 方法,可以重写该方法以自定义时分秒毫秒的回显格式。
212
+ */
213
+ export class Ele extends UiBase<Attrs, Emits> {
214
+ public static readonly tagName = 'dt-period-selector' as const;
215
+
216
+ static get observedAttributes(): string[] {
217
+ return [
218
+ ...(super.observedAttributes as (keyof BaseAttrs)[]),
219
+ 'time-start',
220
+ 'time-end',
221
+ 'min-granularity'
222
+ ] satisfies (keyof Attrs)[];
223
+ }
224
+
225
+ public get timeStart() {
226
+ const v = this._getAttr('time-start', '' + Date.now());
227
+ return new Date(Number.isNaN(+v) ? v : +v);
228
+ }
229
+ public set timeStart(val: number | string | Date) {
230
+ const v = new Date(val);
231
+ if (Number.isNaN(+v)) return;
232
+ this.setAttribute('time-start', +v + '');
233
+ }
234
+ public get timeEnd() {
235
+ const v = this._getAttr('time-end', '' + this.timeStart);
236
+ return new Date(Number.isNaN(+v) ? v : +v);
237
+ }
238
+ public set timeEnd(val: number | string | Date) {
239
+ const v = new Date(val);
240
+ if (Number.isNaN(+v)) return;
241
+ this.setAttribute('time-end', +v + '');
242
+ }
243
+
244
+ protected _style = styleStr;
245
+ protected _template = html`
246
+ <div class="date-echo">
247
+ <div class="start-date-echo-wrapper active">
248
+ <span class="label">Start Date</span>
249
+ <span class="start-date-echo">dd/mm/yyyy</span>
250
+ </div>
251
+ <i class="dividing-line"></i>
252
+ <div class="end-date-echo-wrapper">
253
+ <span class="label">End Date</span>
254
+ <span class="end-date-echo">dd/mm/yyyy</span>
255
+ </div>
256
+ </div><div class="calendars">${['start', 'end']
257
+ .map(
258
+ (s) => html`
259
+ <div class="wrapper ${s}">
260
+ <dt-date-nav
261
+ show-ctrl-btn-month-add
262
+ show-ctrl-btn-month-sub
263
+ ></dt-date-nav>
264
+ <dt-calendar-base data-type="${s}"></dt-calendar-base>
265
+ <dt-popover>
266
+ <div slot="trigger" class="time-echo-wrapper">
267
+ <i class="time-icon"></i>
268
+ <span class="time-echo">hh:mm:ss.sss</span>
269
+ </div>
270
+ <div slot="pop" class="time-selector">
271
+ <h3 class="title">${s === 'start' ? 'Start Time' : 'End Time'}</h3>
272
+ <dt-hhmmss-ms-list-grp></dt-hhmmss-ms-list-grp>
273
+ <button id="time-selector-done-btn" data-type="${s}">Done</button>
274
+ </div>
275
+ </dt-popover>
276
+ </div>`
277
+ )
278
+ .join('')}</div>`;
279
+
280
+ constructor() {
281
+ super();
282
+ this._applyTemplate();
283
+ }
284
+
285
+ private get _startNavEle() {
286
+ return this.shadowRoot?.querySelector(
287
+ '.start dt-date-nav'
288
+ ) as DateNavEle;
289
+ }
290
+ private get _endNavEle() {
291
+ return this.shadowRoot?.querySelector('.end dt-date-nav') as DateNavEle;
292
+ }
293
+ private get _startCalendar() {
294
+ return this.shadowRoot?.querySelector(
295
+ '.start dt-calendar-base'
296
+ ) as CalendarBaseEle;
297
+ }
298
+ private get _endCalendar() {
299
+ return this.shadowRoot?.querySelector(
300
+ '.end dt-calendar-base'
301
+ ) as CalendarBaseEle;
302
+ }
303
+ private get _startTimeSelector() {
304
+ return this.shadowRoot?.querySelector(
305
+ '.start dt-hhmmss-ms-list-grp'
306
+ ) as HhMmSsMsListGrpEle;
307
+ }
308
+ private get _endTimeSelector() {
309
+ return this.shadowRoot?.querySelector(
310
+ '.end dt-hhmmss-ms-list-grp'
311
+ ) as HhMmSsMsListGrpEle;
312
+ }
313
+ private get _startTimePopover() {
314
+ return this.shadowRoot?.querySelector(
315
+ '.start dt-popover'
316
+ ) as PopoverEle;
317
+ }
318
+ private get _endTimePopover() {
319
+ return this.shadowRoot?.querySelector('.end dt-popover') as PopoverEle;
320
+ }
321
+
322
+ // 存放的是结束时间点
323
+ private _selectedDate: Date | null = null;
324
+
325
+ public connectedCallback() {
326
+ if (!super.connectedCallback()) return;
327
+ this._selectedDate = null;
328
+ this._startCalendar.formatter = this._endCalendar.formatter = (
329
+ i: number
330
+ ) => String(i).padStart(2, '0');
331
+ this._render();
332
+ this._startCalendar.addEventListener(
333
+ 'select-time',
334
+ this._onCalendarSelect
335
+ );
336
+ this._endCalendar.addEventListener(
337
+ 'select-time',
338
+ this._onCalendarSelect
339
+ );
340
+ this._startNavEle.addEventListener('change', this._onNavChange);
341
+ this._endNavEle.addEventListener('change', this._onNavChange);
342
+ this._startTimePopover.addEventListener(
343
+ 'open-change',
344
+ this._onTimePopoverOpenChange
345
+ );
346
+ this._endTimePopover.addEventListener(
347
+ 'open-change',
348
+ this._onTimePopoverOpenChange
349
+ );
350
+ this._startCalendar.addEventListener(
351
+ 'hover-item',
352
+ this._onCalendarItemHover
353
+ );
354
+ this._endCalendar.addEventListener(
355
+ 'hover-item',
356
+ this._onCalendarItemHover
357
+ );
358
+ this._startNavEle.addEventListener(
359
+ 'popover-open-change',
360
+ this._onNavOpenToggle
361
+ );
362
+ this._endNavEle.addEventListener(
363
+ 'popover-open-change',
364
+ this._onNavOpenToggle
365
+ );
366
+ this.shadowRoot
367
+ ?.querySelectorAll('#time-selector-done-btn')
368
+ .forEach((btn) => {
369
+ btn.addEventListener('click', this._onTimeSelectorDoneClick);
370
+ });
371
+ }
372
+ public disconnectedCallback() {
373
+ if (!super.disconnectedCallback()) return;
374
+ this._startCalendar.removeEventListener(
375
+ 'select-time',
376
+ this._onCalendarSelect
377
+ );
378
+ this._endCalendar.removeEventListener(
379
+ 'select-time',
380
+ this._onCalendarSelect
381
+ );
382
+ this._startNavEle.removeEventListener('change', this._onNavChange);
383
+ this._endNavEle.removeEventListener('change', this._onNavChange);
384
+ this._startTimePopover.removeEventListener(
385
+ 'open-change',
386
+ this._onTimePopoverOpenChange
387
+ );
388
+ this._endTimePopover.removeEventListener(
389
+ 'open-change',
390
+ this._onTimePopoverOpenChange
391
+ );
392
+ this._startCalendar.removeEventListener(
393
+ 'hover-item',
394
+ this._onCalendarItemHover
395
+ );
396
+ this._endCalendar.removeEventListener(
397
+ 'hover-item',
398
+ this._onCalendarItemHover
399
+ );
400
+ this._startNavEle.removeEventListener(
401
+ 'popover-open-change',
402
+ this._onNavOpenToggle
403
+ );
404
+ this._endNavEle.removeEventListener(
405
+ 'popover-open-change',
406
+ this._onNavOpenToggle
407
+ );
408
+ this.shadowRoot
409
+ ?.querySelectorAll('#time-selector-done-btn')
410
+ .forEach((btn) => {
411
+ btn.removeEventListener('click', this._onTimeSelectorDoneClick);
412
+ });
413
+ }
414
+
415
+ protected _onAttrChanged(name: string, oldValue: string, newValue: string) {
416
+ super._onAttrChanged(name, oldValue, newValue);
417
+ this._render();
418
+ }
419
+
420
+ private _updateNavCtrlBtn() {
421
+ const timeStart = new Date(this._startNavEle.millisecond);
422
+ const timeEnd = new Date(this._endNavEle.millisecond);
423
+ const showCtrlBtn = diffInMonth(timeStart, timeEnd) > 1;
424
+ this._startNavEle.showCtrlBtnMonthAdd = showCtrlBtn;
425
+ this._endNavEle.showCtrlBtnMonthSub = showCtrlBtn;
426
+ }
427
+
428
+ private _render = debounce(() => {
429
+ if (!this.isConnected) return;
430
+ let timeStart = this.timeStart as Date;
431
+ let timeEnd = this.timeEnd as Date;
432
+ if (timeStart > timeEnd) [timeStart, timeEnd] = [timeEnd, timeStart];
433
+ const tz = new Date().getTimezoneOffset() * 60 * 1000;
434
+ this._startNavEle.millisecond =
435
+ this._startCalendar.showingTime =
436
+ this._startCalendar.timeStart =
437
+ this._endCalendar.timeStart =
438
+ +timeStart;
439
+ this._startTimeSelector.millisecond =
440
+ (+timeStart - tz) % (24 * 60 * 60 * 1000);
441
+ this._endCalendar.timeEnd = this._startCalendar.timeEnd = +timeEnd;
442
+ if (diffInMonth(timeStart, timeEnd) <= 1) {
443
+ const nextMonth = new Date(
444
+ timeStart.getFullYear(),
445
+ timeStart.getMonth() + 1
446
+ );
447
+ this._endCalendar.showingTime = nextMonth;
448
+ this._endNavEle.millisecond = +nextMonth;
449
+ } else {
450
+ this._endCalendar.showingTime = timeEnd;
451
+ this._endNavEle.millisecond = +timeEnd;
452
+ }
453
+ this._endTimeSelector.millisecond =
454
+ (+timeEnd - tz) % (24 * 60 * 60 * 1000);
455
+ this.shadowRoot!.querySelector(
456
+ '.wrapper.start .time-echo'
457
+ )!.textContent = this.timeFormatter(timeStart as Date);
458
+ this.shadowRoot!.querySelector('.wrapper.end .time-echo')!.textContent =
459
+ this.timeFormatter(timeEnd as Date);
460
+ this._updateDateEcho();
461
+ this._updateNavCtrlBtn();
462
+ }, 0);
463
+
464
+ private _updateDateEcho() {
465
+ let timeStart = this.timeStart as Date;
466
+ let timeEnd = this.timeEnd as Date;
467
+ if (timeStart > timeEnd) [timeStart, timeEnd] = [timeEnd, timeStart];
468
+ this.shadowRoot!.querySelector('.start-date-echo')!.textContent =
469
+ this.dateFormatter(timeStart);
470
+ this.shadowRoot!.querySelector('.end-date-echo')!.textContent =
471
+ this.dateFormatter(timeEnd);
472
+ this.shadowRoot!.querySelector(
473
+ '.start-date-echo-wrapper'
474
+ )!.classList.toggle('active', !this._selectedDate);
475
+ this.shadowRoot!.querySelector(
476
+ '.end-date-echo-wrapper'
477
+ )!.classList.toggle('active', !!this._selectedDate);
478
+ }
479
+
480
+ private _onCalendarSelect = (e: CalendarBaseEvent['select-time']) => {
481
+ if (this._selectedDate) {
482
+ this._selectedDate = null;
483
+ this.timeEnd = +e.detail + this._endTimeSelector.millisecond;
484
+ } else {
485
+ this._selectedDate = this.timeEnd as unknown as Date;
486
+ this.timeStart = +e.detail + this._startTimeSelector.millisecond;
487
+ }
488
+ };
489
+ private _onCalendarItemHover = (e: CalendarBaseEvent['hover-item']) => {
490
+ if (!this._selectedDate) return;
491
+ this.timeEnd = +e.detail + this._endTimeSelector.millisecond;
492
+ };
493
+ private _onNavChange = (e: DateNavEvent['change']) => {
494
+ const wrapper = closestByEvent(e, '.wrapper');
495
+ if (!wrapper) return;
496
+ const { newStartTime, newEndTime } = e.detail;
497
+ if (wrapper.classList.contains('start')) {
498
+ this._startCalendar.showingTime = +newStartTime;
499
+ } else {
500
+ this._endCalendar.showingTime = +newEndTime;
501
+ }
502
+ this._updateNavCtrlBtn();
503
+ };
504
+ private _onNavOpenToggle = (e: DateNavEvent['popover-open-change']) => {
505
+ if (!(e.target instanceof DateNavEle)) return;
506
+ e.target.nextElementSibling?.classList.toggle('hide', e.detail);
507
+ };
508
+ private _onTimePopoverOpenChange = (e: PopoverEvent['open-change']) => {
509
+ if (!(e.target instanceof PopoverEle)) return;
510
+ if (!e.detail) return this._render(); // for reset time selector value
511
+ e.target
512
+ .querySelectorAll<HhMmSsMsListGrpEle>('dt-hhmmss-ms-list-grp')
513
+ .forEach((ele) => {
514
+ ele.scrollToCurrentItem();
515
+ });
516
+ };
517
+ private _onTimeSelectorDoneClick = (e: Event) => {
518
+ const btn = closestByEvent(e, '#time-selector-done-btn');
519
+ if (!btn) return;
520
+ const type = btn.dataset.type;
521
+ const calcTime = (time: Date, ms: number) => {
522
+ time.setHours(0, 0, 0, 0);
523
+ time.setMilliseconds(ms);
524
+ return time;
525
+ };
526
+ if (type === 'start') {
527
+ this.timeStart = calcTime(
528
+ this.timeStart as Date,
529
+ this._startTimeSelector.millisecond
530
+ );
531
+ this._startTimePopover.open = false;
532
+ } else if (type === 'end') {
533
+ this.timeEnd = calcTime(
534
+ this.timeEnd as Date,
535
+ this._endTimeSelector.millisecond
536
+ );
537
+ this._endTimePopover.open = false;
538
+ }
539
+ };
540
+
541
+ public showCalendarDatePoint() {
542
+ this._render();
543
+ }
544
+
545
+ public timeFormatter = (time: Date) =>
546
+ new Date(+time - new Date().getTimezoneOffset() * 60 * 1000)
547
+ .toISOString()
548
+ .slice(11, 23);
549
+ public dateFormatter = (time: Date) => time.toLocaleDateString('en-GB');
550
+ }
551
+
552
+ Ele.define();
@@ -0,0 +1,127 @@
1
+ import { html } from '../../utils';
2
+ import {
3
+ type BaseAttrs,
4
+ type Emit2EventMap,
5
+ UiBase
6
+ } from '../web-component-base';
7
+
8
+ export interface Attrs extends BaseAttrs {
9
+ open?: boolean;
10
+ disabled?: boolean;
11
+ }
12
+
13
+ export interface Emits {
14
+ 'open-change': boolean;
15
+ }
16
+ export type EventMap = Emit2EventMap<Emits>;
17
+
18
+ /**
19
+ * 点击触发器后气泡弹出
20
+ */
21
+ export class Ele extends UiBase<Attrs, Emits> {
22
+ public static readonly tagName = 'dt-popover' as const;
23
+
24
+ static get observedAttributes(): string[] {
25
+ return [
26
+ ...(super.observedAttributes as (keyof BaseAttrs)[]),
27
+ 'open',
28
+ 'disabled'
29
+ ] satisfies (keyof Attrs)[];
30
+ }
31
+
32
+ protected _template =
33
+ html`<slot name="trigger"></slot><slot name="pop" style="display:none"></slot>`;
34
+
35
+ constructor() {
36
+ super();
37
+ this._applyTemplate();
38
+ }
39
+
40
+ private get _popEle() {
41
+ return this.shadowRoot?.querySelector(
42
+ 'slot[name="pop"]'
43
+ ) as HTMLDivElement;
44
+ }
45
+ private get _triggerEle() {
46
+ return this.shadowRoot?.querySelector(
47
+ 'slot[name="trigger"]'
48
+ ) as HTMLSlotElement;
49
+ }
50
+
51
+ public get open() {
52
+ return this.hasAttribute('open');
53
+ }
54
+ public set open(v: boolean) {
55
+ this.toggleAttribute('open', v);
56
+ }
57
+ public get disabled() {
58
+ return this.hasAttribute('disabled');
59
+ }
60
+ public set disabled(v: boolean) {
61
+ this.toggleAttribute('disabled', v);
62
+ }
63
+ /**
64
+ * toggle open state
65
+ * @returns null if disabled, otherwise the new open state
66
+ */
67
+ public toggleOpen = (force = !this.open) => {
68
+ if (this.disabled) return null;
69
+ return (this.open = force);
70
+ };
71
+
72
+ public connectedCallback() {
73
+ if (!super.connectedCallback()) return;
74
+ this._triggerEle.addEventListener('click', this._onToggleClick);
75
+ }
76
+ public disconnectedCallback() {
77
+ if (!super.disconnectedCallback()) return;
78
+ this._triggerEle.removeEventListener('click', this._onToggleClick);
79
+ }
80
+
81
+ protected _onAttrChanged(name: string, oldValue: string, newValue: string) {
82
+ super._onAttrChanged(name, oldValue, newValue);
83
+ if (name !== 'open') return;
84
+ const isOpen = newValue !== null;
85
+ this._popEle.style.display = !isOpen ? 'none' : '';
86
+ if (typeof document !== 'undefined') {
87
+ setTimeout(() => {
88
+ if (isOpen)
89
+ document.addEventListener('click', this._onDocClick, true);
90
+ else
91
+ document.removeEventListener(
92
+ 'click',
93
+ this._onDocClick,
94
+ true
95
+ );
96
+ });
97
+ }
98
+ this.dispatchEvent('open-change', this.open, true);
99
+ }
100
+
101
+ private _onToggleClick = () => {
102
+ this.toggleOpen();
103
+ };
104
+ private _onDocClick = (e: MouseEvent) => {
105
+ const popEle = this.querySelector('[slot="pop"]');
106
+ if (popEle) {
107
+ if (e.composedPath().includes(popEle)) return;
108
+ if (e.composedPath().includes(this)) {
109
+ const popRect = popEle.getBoundingClientRect();
110
+ if (
111
+ e.clientX >= popRect.left &&
112
+ e.clientX <= popRect.right &&
113
+ e.clientY >= popRect.top &&
114
+ e.clientY <= popRect.bottom
115
+ ) {
116
+ return;
117
+ }
118
+ }
119
+ }
120
+ e.stopPropagation();
121
+ e.preventDefault();
122
+ this.open = false;
123
+ document.removeEventListener('click', this._onDocClick, true);
124
+ };
125
+ }
126
+
127
+ Ele.define();