@sdata/web-vue 1.18.0 → 2.1.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/README.md +3 -7
- package/dist/sd.css +4083 -2512
- package/dist/sd.min.css +1 -1
- package/es/_components/feedback-icon.js +1 -1
- package/es/_components/icon-hover.js +1 -1
- package/es/_components/icon-hover.vue.d.ts +1 -1
- package/es/_components/input-label/input-label.d.ts +1 -1
- package/es/_components/input-label/style/index.css +27 -27
- package/es/_components/picker/input-range.js +1 -1
- package/es/_components/picker/input-range.vue.d.ts +2 -2
- package/es/_components/picker/input.js +1 -1
- package/es/_components/picker/input.vue.d.ts +2 -2
- package/es/_components/resize-trigger.js +1 -1
- package/es/_components/select-view/select-view.d.ts +3 -3
- package/es/_components/select-view/style/index.css +199 -199
- package/es/_components/transition/expand-transition.js +1 -1
- package/es/_components/virtual-list/virtual-list.js +1 -1
- package/es/_components/virtual-list/virtual-list.vue.d.ts +8 -5
- package/es/_components/virtual-list/virtual-list.vue_vue_type_script_lang.js +9 -16
- package/es/_hooks/use-form-item.d.ts +1 -1
- package/es/_hooks/use-scrollbar.d.ts +2 -3
- package/es/_hooks/use-scrollbar.js +4 -8
- package/es/_hooks/use-size.d.ts +1 -1
- package/es/_utils/color.d.ts +9 -0
- package/es/_utils/color.js +38 -2
- package/es/_utils/date.d.ts +1 -2
- package/es/_utils/date.js +74 -25
- package/es/_utils/global-config.d.ts +4 -0
- package/es/_utils/global-config.js +10 -2
- package/es/_utils/omit.js +1 -1
- package/es/_utils/responsive-observe.js +1 -1
- package/es/_utils/virtual-dropdown.js +1 -1
- package/es/_virtual/{_@oxc-project_runtime@0.130.0/helpers → _@oxc-project_runtime@0.133.0/helpers/esm}/asyncToGenerator.js +1 -1
- package/es/_virtual/{_@oxc-project_runtime@0.130.0/helpers → _@oxc-project_runtime@0.133.0/helpers/esm}/defineProperty.js +1 -1
- package/es/_virtual/{_@oxc-project_runtime@0.130.0/helpers → _@oxc-project_runtime@0.133.0/helpers/esm}/extends.js +1 -1
- package/es/_virtual/{_@oxc-project_runtime@0.130.0/helpers → _@oxc-project_runtime@0.133.0/helpers/esm}/objectDestructuringEmpty.js +1 -1
- package/es/_virtual/{_@oxc-project_runtime@0.130.0/helpers → _@oxc-project_runtime@0.133.0/helpers/esm}/objectSpread2.js +1 -1
- package/es/_virtual/{_@oxc-project_runtime@0.130.0/helpers → _@oxc-project_runtime@0.133.0/helpers/esm}/objectWithoutProperties.js +1 -1
- package/es/_virtual/{_@oxc-project_runtime@0.130.0/helpers → _@oxc-project_runtime@0.133.0/helpers/esm}/objectWithoutPropertiesLoose.js +1 -1
- package/es/_virtual/{_@oxc-project_runtime@0.130.0/helpers → _@oxc-project_runtime@0.133.0/helpers/esm}/toPrimitive.js +1 -1
- package/es/_virtual/{_@oxc-project_runtime@0.130.0/helpers → _@oxc-project_runtime@0.133.0/helpers/esm}/toPropertyKey.js +1 -1
- package/es/_virtual/{_@oxc-project_runtime@0.130.0/helpers → _@oxc-project_runtime@0.133.0/helpers/esm}/typeof.js +1 -1
- package/es/affix/affix.js +1 -1
- package/es/affix/affix.vue_vue_type_script_lang.js +1 -1
- package/es/alert/alert.js +1 -1
- package/es/alert/alert.vue.d.ts +1 -1
- package/es/alert/index.d.ts +2 -2
- package/es/alert/style/index.css +28 -28
- package/es/anchor/anchor-link.js +1 -1
- package/es/anchor/anchor.js +1 -1
- package/es/anchor/style/index.css +9 -9
- package/es/auto-complete/auto-complete.d.ts +3 -3
- package/es/auto-complete/auto-complete.js +23 -9
- package/es/auto-complete/index.d.ts +9 -9
- package/es/auto-complete/style/index.css +3 -3
- package/es/avatar/avatar.js +1 -1
- package/es/avatar/avatar.vue_vue_type_script_lang.js +1 -1
- package/es/avatar/style/index.css +15 -15
- package/es/back-top/back-top.js +1 -1
- package/es/back-top/style/index.css +4 -4
- package/es/badge/badge.d.ts +1 -1
- package/es/badge/badge.js +1 -1
- package/es/badge/index.d.ts +3 -3
- package/es/badge/style/index.css +25 -25
- package/es/breadcrumb/style/index.css +12 -12
- package/es/button/button-group.js +1 -1
- package/es/button/button.js +1 -1
- package/es/button/button.vue.d.ts +2 -2
- package/es/button/index.d.ts +6 -6
- package/es/button/style/index.css +37 -37
- package/es/calendar/components/body.js +5 -0
- package/es/calendar/components/body.vue.d.ts +100 -0
- package/es/calendar/components/body.vue_vue_type_script_setup_true_lang.js +158 -0
- package/es/calendar/components/cell.js +5 -0
- package/es/calendar/components/cell.vue.d.ts +220 -0
- package/es/calendar/components/cell.vue_vue_type_script_setup_true_lang.js +813 -0
- package/es/calendar/components/event.js +5 -0
- package/es/calendar/components/event.vue.d.ts +73 -0
- package/es/calendar/components/event.vue_vue_type_script_setup_true_lang.js +290 -0
- package/es/calendar/components/header.js +5 -0
- package/es/calendar/components/header.vue.d.ts +34 -0
- package/es/calendar/components/header.vue_vue_type_script_setup_true_lang.js +84 -0
- package/es/calendar/components/headings-bar.js +5 -0
- package/es/calendar/components/headings-bar.vue.d.ts +40 -0
- package/es/calendar/components/headings-bar.vue_vue_type_script_setup_true_lang.js +201 -0
- package/es/calendar/components/index.js +5 -0
- package/es/calendar/components/index.vue.d.ts +616 -0
- package/es/calendar/components/index.vue_vue_type_script_setup_true_lang.js +314 -0
- package/es/calendar/components/time-column.js +5 -0
- package/es/calendar/components/time-column.vue.d.ts +27 -0
- package/es/calendar/components/time-column.vue_vue_type_script_setup_true_lang.js +66 -0
- package/es/calendar/context.d.ts +16 -0
- package/es/calendar/context.js +5 -0
- package/es/calendar/core/config.d.ts +126 -0
- package/es/calendar/core/config.js +522 -0
- package/es/calendar/core/events.d.ts +1 -0
- package/es/calendar/core/events.js +921 -0
- package/es/calendar/core/i18n.d.ts +1 -0
- package/es/calendar/core/i18n.js +72 -0
- package/es/calendar/core/index.d.ts +112 -0
- package/es/calendar/core/index.js +66 -0
- package/es/calendar/core/props-definitions.d.ts +263 -0
- package/es/calendar/core/props-definitions.js +70 -0
- package/es/calendar/core/view.d.ts +60 -0
- package/es/calendar/core/view.js +761 -0
- package/es/calendar/default-theme.scss +1012 -0
- package/es/calendar/hooks/use-calendar-theme.d.ts +4 -0
- package/es/calendar/hooks/use-calendar-theme.js +32 -0
- package/es/calendar/index.d.ts +836 -98
- package/es/calendar/index.js +3 -3
- package/es/calendar/index.scss +331 -0
- package/es/calendar/modules/drag-and-drop.d.ts +8 -0
- package/es/calendar/modules/drag-and-drop.js +442 -0
- package/es/calendar/style/body.scss +51 -0
- package/es/calendar/style/cell.scss +153 -0
- package/es/calendar/style/css.js +0 -1
- package/es/calendar/style/event.scss +69 -0
- package/es/calendar/style/header.scss +104 -0
- package/es/calendar/style/headings-bar.scss +94 -0
- package/es/calendar/style/index.css +1514 -264
- package/es/calendar/style/index.d.ts +1 -3
- package/es/calendar/style/index.js +0 -1
- package/es/calendar/style/index.scss +9 -496
- package/es/calendar/style/time-column.scss +109 -0
- package/es/calendar/style/token.scss +64 -60
- package/es/calendar/utils/conversions.d.ts +3 -0
- package/es/calendar/utils/conversions.js +31 -0
- package/es/calendar/utils/date.d.ts +26 -0
- package/es/calendar/utils/date.js +253 -0
- package/es/calendar/utils/special-hours-allow-events.d.ts +28 -0
- package/es/calendar/utils/special-hours-allow-events.js +230 -0
- package/es/card/card-grid.js +1 -1
- package/es/card/style/index.css +16 -16
- package/es/carousel/carousel-arrow.js +1 -1
- package/es/carousel/carousel-indicator.js +1 -1
- package/es/carousel/carousel-indicator.vue.d.ts +1 -1
- package/es/carousel/carousel-item.js +1 -1
- package/es/carousel/carousel.js +1 -1
- package/es/carousel/style/index.css +11 -11
- package/es/cascader/cascader-option.d.ts +1 -1
- package/es/cascader/cascader-option.js +1 -1
- package/es/cascader/cascader-panel.vue.d.ts +1 -1
- package/es/cascader/cascader-panel.vue_vue_type_script_setup_true_lang.js +2 -2
- package/es/cascader/cascader.vue.d.ts +5 -5
- package/es/cascader/cascader.vue_vue_type_script_setup_true_lang.js +5 -5
- package/es/cascader/style/index.css +36 -36
- package/es/checkbox/checkbox.d.ts +1 -1
- package/es/checkbox/index.d.ts +2 -2
- package/es/checkbox/style/index.css +18 -18
- package/es/collapse/collapse-item.d.ts +1 -1
- package/es/collapse/collapse.js +1 -1
- package/es/collapse/index.d.ts +1 -1
- package/es/collapse/style/index.css +15 -15
- package/es/color-picker/color-picker.d.ts +1 -1
- package/es/color-picker/color-picker.js +1 -1
- package/es/color-picker/index.d.ts +3 -3
- package/es/color-picker/palette.js +1 -1
- package/es/color-picker/panel.d.ts +1 -1
- package/es/color-picker/panel.js +2 -2
- package/es/color-picker/style/index.css +13 -13
- package/es/color-picker/utils.js +1 -1
- package/es/comment/comment.js +2 -2
- package/es/comment/style/index.css +5 -5
- package/es/components.d.ts +2 -2
- package/es/config-provider/config-provider.js +1 -1
- package/es/config-provider/config-provider.vue.d.ts +1 -1
- package/es/config-provider/context.d.ts +3 -0
- package/es/config-provider/index.d.ts +3 -3
- package/es/config-provider/theme-provider.vue_vue_type_script_setup_true_lang.js +2 -2
- package/es/config-provider/theme.js +1 -1
- package/es/copy/copy.vue_vue_type_script_setup_true_lang.js +3 -3
- package/es/cropper/cropper.vue_vue_type_script_setup_true_lang.js +3 -3
- package/es/cropper/style/index.css +3 -3
- package/es/date-picker/hooks/use-range-time-picker-value.js +1 -1
- package/es/date-picker/index.d.ts +48 -48
- package/es/date-picker/panels/body.js +1 -1
- package/es/date-picker/panels/date/index.js +2 -2
- package/es/date-picker/panels/date/index.vue.d.ts +6 -6
- package/es/date-picker/panels/date/index.vue_vue_type_script_lang.js +1 -1
- package/es/date-picker/panels/footer.js +1 -1
- package/es/date-picker/panels/footer.vue.d.ts +9 -9
- package/es/date-picker/panels/header.js +1 -1
- package/es/date-picker/panels/month/index.js +2 -2
- package/es/date-picker/panels/quarter/index.js +2 -2
- package/es/date-picker/panels/shortcuts.js +1 -1
- package/es/date-picker/panels/shortcuts.vue.d.ts +6 -6
- package/es/date-picker/panels/week/index.js +1 -1
- package/es/date-picker/panels/week/index.vue.d.ts +6 -6
- package/es/date-picker/panels/week-list.js +1 -1
- package/es/date-picker/panels/year/index.js +2 -2
- package/es/date-picker/picker-panel.js +1 -1
- package/es/date-picker/picker-panel.vue.d.ts +28 -28
- package/es/date-picker/picker.js +2 -2
- package/es/date-picker/picker.vue.d.ts +46 -46
- package/es/date-picker/picker.vue_vue_type_script_lang.js +1 -1
- package/es/date-picker/range-picker-panel.js +1 -1
- package/es/date-picker/range-picker-panel.vue.d.ts +29 -29
- package/es/date-picker/range-picker-panel.vue_vue_type_script_lang.js +1 -1
- package/es/date-picker/range-picker.js +2 -2
- package/es/date-picker/range-picker.vue.d.ts +48 -48
- package/es/date-picker/range-picker.vue_vue_type_script_lang.js +1 -1
- package/es/date-picker/style/index.css +72 -72
- package/es/descriptions/descriptions-item.js +1 -1
- package/es/descriptions/descriptions.d.ts +2 -2
- package/es/descriptions/descriptions.js +1 -1
- package/es/descriptions/index.d.ts +6 -6
- package/es/descriptions/style/index.css +10 -10
- package/es/divider/divider.d.ts +1 -1
- package/es/divider/index.d.ts +3 -3
- package/es/divider/style/index.css +4 -4
- package/es/drawer/drawer.js +9 -2
- package/es/drawer/drawer.vue.d.ts +2905 -10
- package/es/drawer/drawer.vue_vue_type_script_lang.js +26 -7
- package/es/drawer/index.d.ts +6550 -764
- package/es/drawer/index.js +2 -2
- package/es/drawer/style/index.css +12 -7
- package/es/drawer/style/index.scss +6 -0
- package/es/dropdown/dropdown-button.js +1 -1
- package/es/dropdown/dropdown-button.vue.d.ts +24 -21
- package/es/dropdown/dropdown-group.js +1 -1
- package/es/dropdown/dropdown-option.js +1 -1
- package/es/dropdown/dropdown-option.vue.d.ts +1 -1
- package/es/dropdown/dropdown-panel.js +1 -1
- package/es/dropdown/dropdown-panel.vue.d.ts +6 -3
- package/es/dropdown/dropdown-submenu.js +1 -1
- package/es/dropdown/dropdown-submenu.vue.d.ts +18 -15
- package/es/dropdown/dropdown.js +1 -1
- package/es/dropdown/dropdown.vue.d.ts +16 -13
- package/es/dropdown/index.d.ts +78 -66
- package/es/dropdown/style/index.css +1 -1
- package/es/ellipsis/ellipsis.js +1 -1
- package/es/ellipsis/ellipsis.vue.d.ts +24 -24
- package/es/ellipsis/ellipsis.vue_vue_type_script_lang.js +2 -2
- package/es/ellipsis/index.d.ts +96 -96
- package/es/ellipsis/performant-ellipsis.js +1 -1
- package/es/ellipsis/performant-ellipsis.vue.d.ts +24 -24
- package/es/ellipsis/performant-ellipsis.vue_vue_type_script_lang.js +1 -1
- package/es/empty/style/index.css +2 -2
- package/es/form/form-item-label.js +1 -1
- package/es/form/form-item-label.vue.d.ts +24 -24
- package/es/form/form-item-message.js +1 -1
- package/es/form/form-item.js +1 -1
- package/es/form/form-item.vue.d.ts +29 -29
- package/es/form/form-item.vue_vue_type_script_lang.js +3 -3
- package/es/form/form.js +1 -1
- package/es/form/form.vue.d.ts +1 -1
- package/es/form/index.d.ts +35 -35
- package/es/form/style/index.css +6 -6
- package/es/grid/grid-col.js +1 -1
- package/es/grid/grid-col.vue_vue_type_script_lang.js +1 -1
- package/es/grid/grid-item.js +1 -1
- package/es/grid/grid-item.vue_vue_type_script_lang.js +1 -1
- package/es/grid/grid-row.js +1 -1
- package/es/grid/grid-row.vue.d.ts +4 -4
- package/es/grid/grid.js +1 -1
- package/es/grid/index.d.ts +4 -4
- package/es/icon/icon-calendar/icon-calendar.js +1 -1
- package/es/icon/icon-caret-down/icon-caret-down.js +1 -1
- package/es/icon/icon-caret-left/icon-caret-left.js +1 -1
- package/es/icon/icon-caret-right/icon-caret-right.js +1 -1
- package/es/icon/icon-caret-up/icon-caret-up.js +1 -1
- package/es/icon/icon-check/icon-check.js +1 -1
- package/es/icon/icon-check-circle-fill/icon-check-circle-fill.js +1 -1
- package/es/icon/icon-clock-circle/icon-clock-circle.js +1 -1
- package/es/icon/icon-close/icon-close.js +1 -1
- package/es/icon/icon-close-circle-fill/icon-close-circle-fill.js +1 -1
- package/es/icon/icon-copy/icon-copy.js +1 -1
- package/es/icon/icon-delete/icon-delete.js +1 -1
- package/es/icon/icon-double-left/icon-double-left.js +1 -1
- package/es/icon/icon-double-right/icon-double-right.js +1 -1
- package/es/icon/icon-down/icon-down.js +1 -1
- package/es/icon/icon-drag-dot/icon-drag-dot.js +1 -1
- package/es/icon/icon-drag-dot-vertical/icon-drag-dot-vertical.js +1 -1
- package/es/icon/icon-edit/icon-edit.js +1 -1
- package/es/icon/icon-empty/icon-empty.js +1 -1
- package/es/icon/icon-exclamation/icon-exclamation.js +1 -1
- package/es/icon/icon-exclamation-circle-fill/icon-exclamation-circle-fill.js +1 -1
- package/es/icon/icon-eye/icon-eye.js +1 -1
- package/es/icon/icon-eye-invisible/icon-eye-invisible.js +1 -1
- package/es/icon/icon-face-frown-fill/icon-face-frown-fill.js +1 -1
- package/es/icon/icon-face-meh-fill/icon-face-meh-fill.js +1 -1
- package/es/icon/icon-face-smile-fill/icon-face-smile-fill.js +1 -1
- package/es/icon/icon-file/icon-file.js +1 -1
- package/es/icon/icon-file-audio/icon-file-audio.js +1 -1
- package/es/icon/icon-file-image/icon-file-image.js +1 -1
- package/es/icon/icon-file-pdf/icon-file-pdf.js +1 -1
- package/es/icon/icon-file-video/icon-file-video.js +1 -1
- package/es/icon/icon-filter/icon-filter.js +1 -1
- package/es/icon/icon-fullscreen/icon-fullscreen.js +1 -1
- package/es/icon/icon-image-close/icon-image-close.js +1 -1
- package/es/icon/icon-info/icon-info.js +1 -1
- package/es/icon/icon-info-circle-fill/icon-info-circle-fill.js +1 -1
- package/es/icon/icon-left/icon-left.js +1 -1
- package/es/icon/icon-link/icon-link.js +1 -1
- package/es/icon/icon-loading/icon-loading.js +1 -1
- package/es/icon/icon-menu-fold/icon-menu-fold.js +1 -1
- package/es/icon/icon-menu-unfold/icon-menu-unfold.js +1 -1
- package/es/icon/icon-minus/icon-minus.js +1 -1
- package/es/icon/icon-more/icon-more.js +1 -1
- package/es/icon/icon-oblique-line/icon-oblique-line.js +1 -1
- package/es/icon/icon-original-size/icon-original-size.js +1 -1
- package/es/icon/icon-pause/icon-pause.js +1 -1
- package/es/icon/icon-play-arrow-fill/icon-play-arrow-fill.js +1 -1
- package/es/icon/icon-plus/icon-plus.js +1 -1
- package/es/icon/icon-question-circle/icon-question-circle.js +1 -1
- package/es/icon/icon-right/icon-right.js +1 -1
- package/es/icon/icon-rotate-left/icon-rotate-left.js +1 -1
- package/es/icon/icon-rotate-right/icon-rotate-right.js +1 -1
- package/es/icon/icon-search/icon-search.js +1 -1
- package/es/icon/icon-star-fill/icon-star-fill.js +1 -1
- package/es/icon/icon-to-top/icon-to-top.js +1 -1
- package/es/icon/icon-up/icon-up.js +1 -1
- package/es/icon/icon-upload/icon-upload.js +1 -1
- package/es/icon/icon-zoom-in/icon-zoom-in.js +1 -1
- package/es/icon/icon-zoom-out/icon-zoom-out.js +1 -1
- package/es/icon-component/icon.js +1 -1
- package/es/icon.js +292 -292
- package/es/image/image-footer.js +1 -1
- package/es/image/image.js +2 -2
- package/es/image/image.vue.d.ts +24 -24
- package/es/image/preview-action.d.ts +24 -24
- package/es/image/preview-arrow.js +1 -1
- package/es/image/preview-group.js +2 -2
- package/es/image/preview-group.vue.d.ts +25 -25
- package/es/image/preview-toolbar.js +1 -1
- package/es/image/preview-toolbar.vue.d.ts +24 -24
- package/es/image/preview.js +1 -1
- package/es/image/preview.vue.d.ts +24 -24
- package/es/image/preview.vue_vue_type_script_lang.js +1 -1
- package/es/image/style/index.css +32 -32
- package/es/index.css +4083 -2512
- package/es/index.d.ts +8 -2
- package/es/index.js +11 -10
- package/es/index.scss +3 -1
- package/es/input/index.d.ts +9 -9
- package/es/input/input-group.js +1 -1
- package/es/input/input-password.js +1 -1
- package/es/input/input-password.vue.d.ts +3 -3
- package/es/input/input.d.ts +2 -2
- package/es/input/input.js +1 -1
- package/es/input/style/index.css +50 -50
- package/es/input-number/index.d.ts +6 -6
- package/es/input-number/input-number.d.ts +2 -2
- package/es/input-number/input-number.js +1 -1
- package/es/input-number/style/index.css +16 -16
- package/es/input-tag/index.d.ts +6 -6
- package/es/input-tag/input-tag.d.ts +2 -2
- package/es/input-tag/input-tag.js +1 -1
- package/es/input-tag/style/index.css +172 -172
- package/es/input-tag/utils.js +1 -1
- package/es/json-form/json-form-component.vue_vue_type_script_setup_true_lang.js +3 -3
- package/es/json-form/json-form-item.vue_vue_type_script_setup_true_lang.js +3 -3
- package/es/json-form/json-form.vue_vue_type_script_setup_true_lang.js +3 -3
- package/es/json-form/utils.js +3 -3
- package/es/layout/content.js +1 -1
- package/es/layout/footer.js +1 -1
- package/es/layout/header.vue.d.ts +1 -1
- package/es/layout/header.vue_vue_type_script_setup_true_lang.js +2 -2
- package/es/layout/index.d.ts +21 -21
- package/es/layout/layout.js +1 -1
- package/es/layout/sider.js +1 -1
- package/es/layout/sider.vue.d.ts +16 -16
- package/es/layout/sider.vue_vue_type_script_lang.js +1 -1
- package/es/layout/style/index.css +12 -12
- package/es/link/index.d.ts +3 -3
- package/es/link/link.vue.d.ts +1 -1
- package/es/link/link.vue_vue_type_script_setup_true_lang.js +2 -2
- package/es/link/style/index.css +23 -23
- package/es/list/index.d.ts +9 -9
- package/es/list/list-item-meta.js +1 -1
- package/es/list/list.d.ts +3 -3
- package/es/list/list.js +4 -4
- package/es/list/style/index.css +9 -9
- package/es/locale/interface.d.ts +6 -0
- package/es/locale/lang/ar-eg.js +7 -1
- package/es/locale/lang/de-de.js +7 -1
- package/es/locale/lang/en-us.js +7 -1
- package/es/locale/lang/es-es.js +7 -1
- package/es/locale/lang/fr-fr.js +7 -1
- package/es/locale/lang/id-id.js +7 -1
- package/es/locale/lang/it-it.js +7 -1
- package/es/locale/lang/ja-jp.js +7 -1
- package/es/locale/lang/km-kh.js +7 -1
- package/es/locale/lang/ko-kr.js +7 -1
- package/es/locale/lang/ms-my.js +7 -1
- package/es/locale/lang/nl-nl.js +7 -1
- package/es/locale/lang/pt-pt.js +7 -1
- package/es/locale/lang/ru-ru.js +7 -1
- package/es/locale/lang/th-th.js +7 -1
- package/es/locale/lang/vi-vn.js +7 -1
- package/es/locale/lang/zh-cn.js +7 -1
- package/es/locale/lang/zh-tw.js +7 -1
- package/es/mention/index.d.ts +9 -9
- package/es/mention/mention.d.ts +3 -3
- package/es/mention/mention.js +24 -10
- package/es/menu/base-menu.js +1 -1
- package/es/menu/indent.js +1 -1
- package/es/menu/item-group.js +1 -1
- package/es/menu/item-group.vue.d.ts +48 -48
- package/es/menu/item.js +1 -1
- package/es/menu/menu.js +1 -1
- package/es/menu/style/index.css +62 -62
- package/es/menu/sub-menu-inline.js +1 -1
- package/es/menu/sub-menu-inline.vue.d.ts +48 -48
- package/es/menu/sub-menu-pop.js +1 -1
- package/es/menu/sub-menu-pop.vue.d.ts +57 -57
- package/es/menu/sub-menu.js +1 -1
- package/es/message/index.js +1 -1
- package/es/message/message-list.d.ts +1 -1
- package/es/message/message.js +1 -1
- package/es/message/message.vue.d.ts +1 -1
- package/es/message/style/index.css +26 -26
- package/es/modal/index.d.ts +6368 -570
- package/es/modal/index.js +2 -2
- package/es/modal/modal.js +15 -4
- package/es/modal/modal.vue.d.ts +2907 -8
- package/es/modal/modal.vue_vue_type_script_lang.js +28 -5
- package/es/modal/style/index.css +28 -12
- package/es/modal/style/index.scss +23 -0
- package/es/notification/index.js +1 -1
- package/es/notification/notification.js +1 -1
- package/es/notification/notification.vue.d.ts +1 -1
- package/es/notification/style/index.css +26 -26
- package/es/page-header/index.d.ts +2 -2
- package/es/page-header/page-header.js +1 -1
- package/es/page-header/page-header.vue.d.ts +1 -1
- package/es/page-header/style/index.css +6 -6
- package/es/pagination/page-item-ellipsis.js +1 -1
- package/es/pagination/page-item-step.js +1 -1
- package/es/pagination/page-item.js +1 -1
- package/es/pagination/page-jumper.js +1 -1
- package/es/pagination/page-jumper.vue.d.ts +6 -6
- package/es/pagination/page-options.js +1 -1
- package/es/pagination/page-options.vue.d.ts +647 -469
- package/es/pagination/style/index.css +21 -21
- package/es/popconfirm/index.d.ts +33 -33
- package/es/popconfirm/popconfirm.js +1 -1
- package/es/popconfirm/popconfirm.vue.d.ts +16 -16
- package/es/popconfirm/popconfirm.vue_vue_type_script_lang.js +1 -1
- package/es/popconfirm/style/index.css +11 -11
- package/es/popover/index.d.ts +899 -21
- package/es/popover/popover.js +7 -3
- package/es/popover/popover.vue.d.ts +451 -10
- package/es/popover/popover.vue_vue_type_script_lang.js +15 -3
- package/es/popover/style/index.css +7 -7
- package/es/popover/style/index.d.ts +1 -0
- package/es/progress/circle.js +1 -1
- package/es/progress/circle.vue.d.ts +1 -1
- package/es/progress/index.d.ts +7 -7
- package/es/progress/line.js +1 -1
- package/es/progress/line.vue.d.ts +1 -1
- package/es/progress/line.vue_vue_type_script_lang.js +1 -1
- package/es/progress/progress.js +1 -1
- package/es/progress/progress.vue.d.ts +3 -3
- package/es/progress/steps.js +1 -1
- package/es/progress/style/index.css +32 -32
- package/es/qr-code/index.d.ts +294 -0
- package/es/qr-code/index.js +10 -0
- package/es/qr-code/qr-code-status.js +5 -0
- package/es/qr-code/qr-code-status.vue.d.ts +8 -0
- package/es/qr-code/qr-code-status.vue_vue_type_script_setup_true_lang.js +30 -0
- package/es/qr-code/qr-code.js +5 -0
- package/es/qr-code/qr-code.vue.d.ts +167 -0
- package/es/qr-code/qr-code.vue_vue_type_script_setup_true_lang.js +313 -0
- package/es/qr-code/style/css.js +2 -0
- package/es/qr-code/style/index.css +106 -0
- package/es/qr-code/style/index.d.ts +2 -0
- package/es/qr-code/style/index.js +2 -0
- package/es/qr-code/style/index.scss +111 -0
- package/es/qr-code/style/token.scss +36 -0
- package/es/qr-code/types.d.ts +19 -0
- package/es/radio/index.d.ts +5 -5
- package/es/radio/radio.d.ts +2 -2
- package/es/radio/style/index.css +33 -33
- package/es/rate/index.d.ts +3 -3
- package/es/rate/rate.d.ts +1 -1
- package/es/rate/style/index.css +3 -3
- package/es/resize-box/index.d.ts +6 -6
- package/es/resize-box/resize-box.js +1 -1
- package/es/resize-box/resize-box.vue.d.ts +2 -2
- package/es/resize-box/resize-box.vue_vue_type_script_lang.js +1 -1
- package/es/resize-box/style/index.css +2 -2
- package/es/result/result.js +1 -1
- package/es/result/style/index.css +2 -2
- package/es/scrollbar/index.d.ts +6 -3
- package/es/scrollbar/scrollbar.js +2 -1
- package/es/scrollbar/scrollbar.vue.d.ts +2 -1
- package/es/scrollbar/scrollbar.vue_vue_type_script_lang.js +52 -2
- package/es/scrollbar/style/index.css +13 -13
- package/es/sd-vue.js +13 -12
- package/es/secret/secret.vue_vue_type_script_setup_true_lang.js +3 -3
- package/es/secret/style/index.css +4 -4
- package/es/select/context.d.ts +1 -4
- package/es/select/hooks/use-options.d.ts +1 -4
- package/es/select/hooks/use-options.js +2 -23
- package/es/select/hooks/use-select.d.ts +1 -3
- package/es/select/hooks/use-select.js +2 -7
- package/es/select/index.d.ts +647 -474
- package/es/select/index.js +5 -13
- package/es/select/interface.d.ts +1 -1
- package/es/select/select-dropdown.js +3 -2
- package/es/select/select-dropdown.vue.d.ts +56 -54
- package/es/select/select-dropdown.vue_vue_type_script_lang.js +2 -3
- package/es/select/select.d.ts +260 -18
- package/es/select/select.js +44 -23
- package/es/select/style/index.css +14 -14
- package/es/select/utils.d.ts +1 -1
- package/es/select/utils.js +1 -1
- package/es/skeleton/line.js +1 -1
- package/es/skeleton/shape.js +1 -1
- package/es/skeleton/skeleton.js +1 -1
- package/es/skeleton/style/index.css +4 -4
- package/es/slider/index.d.ts +67 -67
- package/es/slider/slider-button.js +1 -1
- package/es/slider/slider-button.vue.d.ts +25 -25
- package/es/slider/slider-dots.js +1 -1
- package/es/slider/slider-input.js +1 -1
- package/es/slider/slider-input.vue.d.ts +7 -7
- package/es/slider/slider-marks.js +1 -1
- package/es/slider/slider-ticks.js +1 -1
- package/es/slider/slider.js +1 -1
- package/es/slider/slider.vue.d.ts +33 -33
- package/es/slider/style/index.css +18 -18
- package/es/space/index.d.ts +9 -9
- package/es/space/space.d.ts +2 -2
- package/es/spin/index.d.ts +1 -0
- package/es/spin/style/index.css +9 -9
- package/es/split/split.js +1 -1
- package/es/split/split.vue_vue_type_script_lang.js +1 -1
- package/es/split/style/index.css +2 -2
- package/es/statistic/countdown.js +1 -1
- package/es/statistic/countdown.vue.d.ts +1 -1
- package/es/statistic/countdown.vue_vue_type_script_lang.js +5 -5
- package/es/statistic/index.d.ts +1 -1
- package/es/statistic/statistic.js +1 -1
- package/es/statistic/statistic.vue_vue_type_script_lang.js +2 -2
- package/es/statistic/style/index.css +4 -4
- package/es/steps/index.d.ts +4 -4
- package/es/steps/step.js +1 -1
- package/es/steps/step.vue.d.ts +1 -1
- package/es/steps/steps.js +1 -1
- package/es/steps/steps.vue.d.ts +1 -1
- package/es/steps/style/index.css +79 -79
- package/es/style/color/colors.scss +1 -1
- package/es/style/theme/global.scss +8 -8
- package/es/style/theme/index.scss +4 -12
- package/es/style/theme/z-index.js +1 -2
- package/es/switch/style/index.css +30 -30
- package/es/switch/switch.js +1 -1
- package/es/switch/switch.vue_vue_type_script_lang.js +1 -1
- package/es/table/index.d.ts +14 -14
- package/es/table/style/index.css +65 -65
- package/es/table/table-operation-td.d.ts +7 -7
- package/es/table/table-operation-td.js +1 -1
- package/es/table/table-operation-th.js +1 -1
- package/es/table/table-td.d.ts +1 -1
- package/es/table/table-td.js +1 -1
- package/es/table/table-th.d.ts +1 -1
- package/es/table/table-th.js +2 -2
- package/es/table/table.d.ts +5 -5
- package/es/table/table.js +12 -14
- package/es/table/utils.js +1 -1
- package/es/tabs/index.d.ts +9 -9
- package/es/tabs/style/index.css +56 -56
- package/es/tabs/tab-pane.js +1 -1
- package/es/tabs/tab-pane.vue_vue_type_script_lang.js +1 -1
- package/es/tabs/tabs-nav-ink.js +1 -1
- package/es/tabs/tabs-nav.d.ts +1 -1
- package/es/tabs/tabs-tab.js +1 -1
- package/es/tabs/tabs-tab.vue.d.ts +1 -1
- package/es/tabs/tabs.d.ts +3 -3
- package/es/tag/index.d.ts +66 -29688
- package/es/tag/interface.d.ts +2 -0
- package/es/tag/style/index.css +134 -134
- package/es/tag/style/index.scss +33 -13
- package/es/tag/tag.js +2 -64
- package/es/tag/tag.vue.d.ts +53 -11936
- package/es/tag/tag.vue_vue_type_script_setup_true_lang.js +368 -0
- package/es/tag-group/tag-group.vue_vue_type_script_setup_true_lang.js +4 -4
- package/es/textarea/index.d.ts +8 -8
- package/es/textarea/style/index.css +28 -28
- package/es/textarea/textarea.js +1 -1
- package/es/textarea/textarea.vue.d.ts +3 -3
- package/es/textarea/textarea.vue_vue_type_script_lang.js +1 -1
- package/es/time-picker/hooks/use-time-list.js +1 -1
- package/es/time-picker/index.d.ts +56 -56
- package/es/time-picker/panel.js +1 -1
- package/es/time-picker/panel.vue.d.ts +6 -6
- package/es/time-picker/range-panel.d.ts +6 -6
- package/es/time-picker/range-panel.js +1 -1
- package/es/time-picker/style/index.css +11 -11
- package/es/time-picker/time-column.js +1 -1
- package/es/time-picker/time-picker.js +2 -2
- package/es/time-picker/time-picker.vue.d.ts +27 -27
- package/es/timeline/item.js +1 -1
- package/es/timeline/item.vue_vue_type_script_lang.js +1 -1
- package/es/timeline/style/index.css +11 -11
- package/es/tooltip/index.d.ts +24 -24
- package/es/tooltip/style/index.css +3 -3
- package/es/tooltip/tooltip.js +1 -1
- package/es/tooltip/tooltip.vue.d.ts +11 -11
- package/es/tooltip/tooltip.vue_vue_type_script_lang.js +1 -1
- package/es/tour/index.d.ts +664 -0
- package/es/tour/index.js +10 -0
- package/es/tour/style/css.js +1 -0
- package/es/tour/style/index.css +226 -0
- package/es/tour/style/index.d.ts +1 -0
- package/es/tour/style/index.js +1 -0
- package/es/tour/style/index.scss +218 -0
- package/es/tour/style/token.scss +27 -0
- package/es/tour/tour.js +5 -0
- package/es/tour/tour.vue.d.ts +411 -0
- package/es/tour/tour.vue_vue_type_script_setup_true_lang.js +1219 -0
- package/es/tour/types.d.ts +143 -0
- package/es/transfer/index.d.ts +51 -45
- package/es/transfer/style/index.css +20 -20
- package/es/transfer/transfer-view.js +2 -3
- package/es/transfer/transfer-view.vue.d.ts +18 -15
- package/es/transfer/transfer-view.vue_vue_type_script_lang.js +1 -1
- package/es/transfer/transfer.js +1 -1
- package/es/transfer/transfer.vue.d.ts +25 -22
- package/es/tree/base-node.js +1 -1
- package/es/tree/base-node.vue.d.ts +2 -2
- package/es/tree/expand-transition.js +1 -1
- package/es/tree/node.js +1 -1
- package/es/tree/style/index.css +25 -25
- package/es/tree/transition-node-list.js +1 -1
- package/es/tree/transition-node-list.vue.d.ts +2 -2
- package/es/tree/tree.js +1 -1
- package/es/tree/tree.vue.d.ts +12 -9
- package/es/tree/tree.vue_vue_type_script_lang.js +2 -2
- package/es/tree/utils/tree-data.js +1 -1
- package/es/tree-select/hooks/use-selected-state.js +1 -1
- package/es/tree-select/panel.js +4 -7
- package/es/tree-select/style/index.css +5 -5
- package/es/tree-select/tree-select.js +2 -2
- package/es/tree-select/tree-select.vue.d.ts +21 -21
- package/es/tree-select/tree-select.vue_vue_type_script_lang.js +1 -1
- package/es/trigger/index.d.ts +9 -9
- package/es/trigger/style/index.css +5 -5
- package/es/trigger/trigger.d.ts +3 -3
- package/es/trigger/trigger.js +1 -1
- package/es/trigger/utils.js +1 -1
- package/es/typography/base.d.ts +4 -4
- package/es/typography/base.js +1 -1
- package/es/typography/edit-content.js +1 -1
- package/es/typography/edit-content.vue.d.ts +28 -28
- package/es/typography/operations.js +1 -1
- package/es/typography/operations.vue.d.ts +24 -24
- package/es/typography/style/index.css +22 -22
- package/es/typography/typography.js +1 -1
- package/es/upload/index.d.ts +6 -6
- package/es/upload/style/index.css +51 -51
- package/es/upload/upload-button.d.ts +1 -1
- package/es/upload/upload.d.ts +2 -2
- package/es/upload/upload.js +2 -2
- package/es/verification-code/index.d.ts +3 -3
- package/es/verification-code/verification-code.d.ts +1 -1
- package/es/watermark/hooks/use-mutation-observer.js +1 -1
- package/es/watermark/watermark.js +1 -1
- package/json/vetur-attributes.json +125 -107
- package/json/vetur-tags.json +39 -36
- package/json/web-types.json +181 -162
- package/package.json +19 -15
- package/es/calendar/calendar.d.ts +0 -104
- package/es/calendar/calendar.js +0 -207
- package/es/calendar/header.d.ts +0 -104
- package/es/calendar/header.js +0 -131
- package/es/calendar/hooks/useCellClassName.d.ts +0 -19
- package/es/calendar/hooks/useCellClassName.js +0 -43
- package/es/calendar/month.d.ts +0 -83
- package/es/calendar/month.js +0 -149
- package/es/calendar/week.d.ts +0 -61
- package/es/calendar/week.js +0 -45
- package/es/calendar/year.d.ts +0 -69
- package/es/calendar/year.js +0 -101
- package/es/select/optgroup.js +0 -10
- package/es/select/optgroup.vue.d.ts +0 -13
- package/es/select/optgroup.vue_vue_type_script_lang.js +0 -23
- package/es/select/option.js +0 -51
- package/es/select/option.vue.d.ts +0 -299
- package/es/select/option.vue_vue_type_script_lang.js +0 -149
- package/es/tag/tag.vue_vue_type_script_lang.js +0 -264
|
@@ -0,0 +1,921 @@
|
|
|
1
|
+
import { computed, reactive, shallowReactive, watch } from 'vue';
|
|
2
|
+
|
|
3
|
+
import { percentageToMinutes } from '../utils/conversions';
|
|
4
|
+
import {
|
|
5
|
+
clampResizeProposedRange,
|
|
6
|
+
eventRangeViolatesAllowEvents,
|
|
7
|
+
} from '../utils/special-hours-allow-events';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* useEvents is a composable function that manages events for the Calendar component.
|
|
11
|
+
* It provides methods to create, delete, and retrieve events, as well as normalize event dates.
|
|
12
|
+
*
|
|
13
|
+
* @param {Object} calendar - The Calendar instance.
|
|
14
|
+
* @returns {Object} An object containing methods and computed properties for managing events.
|
|
15
|
+
*/
|
|
16
|
+
export const useEvents = (calendar) => {
|
|
17
|
+
const { dateUtils, config } = calendar;
|
|
18
|
+
const prefixCls = calendar.prefixCls;
|
|
19
|
+
let uid = 0; // Internal unique ID events counter.
|
|
20
|
+
|
|
21
|
+
// Use shallowReactive for the events index so that mutations to individual event
|
|
22
|
+
// properties (start/end during drag/resize) do NOT trigger a full re-index cascade.
|
|
23
|
+
// The index is only rebuilt when events are added or removed.
|
|
24
|
+
const eventsIndex = shallowReactive({
|
|
25
|
+
byYear: {},
|
|
26
|
+
byDate: {},
|
|
27
|
+
recurring: [],
|
|
28
|
+
multiday: [],
|
|
29
|
+
byId: {},
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// Build/rebuild the events index from the config.events source of truth.
|
|
33
|
+
// Called initially and whenever events are added or removed.
|
|
34
|
+
const buildEventsIndex = () => {
|
|
35
|
+
const newByYear = {};
|
|
36
|
+
const newByDate = {};
|
|
37
|
+
const newRecurring = [];
|
|
38
|
+
const newMultiday = [];
|
|
39
|
+
const newById = {};
|
|
40
|
+
|
|
41
|
+
// First sort the events by start date so the latest comes last in the DOM and has a natural
|
|
42
|
+
// higher z-index for readability when overlapping.
|
|
43
|
+
// Use stable sort to avoid unnecessary reordering when dates haven't changed.
|
|
44
|
+
const sortedEvents = config.events.slice().sort((a, b) => (a.start - b.start < 0 ? -1 : 1));
|
|
45
|
+
|
|
46
|
+
for (let event of sortedEvents) {
|
|
47
|
+
// Check if event needs processing.
|
|
48
|
+
// --------------------------------------------------
|
|
49
|
+
// First check if dates are strings (need normalization) or methods are missing.
|
|
50
|
+
const hasStringDates = typeof event.start === 'string' || typeof event.end === 'string';
|
|
51
|
+
const missingMethods = !event._?.register || !event.isOverlapping || !event.delete;
|
|
52
|
+
|
|
53
|
+
// Only check cached timestamps if we have Date objects and cached values.
|
|
54
|
+
let datesChanged = false;
|
|
55
|
+
if (!hasStringDates && event._?.cachedStart && event._?.cachedEnd) {
|
|
56
|
+
datesChanged =
|
|
57
|
+
event.start.getTime() !== event._?.cachedStart ||
|
|
58
|
+
event.end.getTime() !== event._?.cachedEnd;
|
|
59
|
+
}
|
|
60
|
+
// --------------------------------------------------
|
|
61
|
+
|
|
62
|
+
// If any of the conditions are true, we need to process the event.
|
|
63
|
+
if (hasStringDates || missingMethods || datesChanged) {
|
|
64
|
+
// Make sure the dates are valid Date objects, and add formatted start date in `event._`.
|
|
65
|
+
if (!normalizeEventDates(event)) continue; // Skip if invalid.
|
|
66
|
+
|
|
67
|
+
injectMetaData(event); // Inject core logic and utilities in each event.
|
|
68
|
+
|
|
69
|
+
// Cache the timestamps to detect future changes.
|
|
70
|
+
event._.cachedStart = event.start.getTime();
|
|
71
|
+
event._.cachedEnd = event.end.getTime();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
newById[event._.id] = event; // Save and index the event in the byId map.
|
|
75
|
+
|
|
76
|
+
if (event.recurring) {
|
|
77
|
+
newRecurring.push(event._.id);
|
|
78
|
+
// @todo: Possibly do other things here.
|
|
79
|
+
}
|
|
80
|
+
// Remove 1ms in case the event ends at next midnight 00:00:00.
|
|
81
|
+
else if (!dateUtils.isSameDate(event.start, new Date(event.end.getTime() - 1))) {
|
|
82
|
+
event._.multiday = config.multidayEvents;
|
|
83
|
+
if (!config.multidayEvents) {
|
|
84
|
+
console.info(
|
|
85
|
+
'Calendar: Multi-day events provided without being enabled. Truncating event end to next midnight.',
|
|
86
|
+
);
|
|
87
|
+
event.end = new Date(new Date(event.start).setHours(23, 59, 59, 999));
|
|
88
|
+
injectMetaData(event); // Re-inject the event metadata for the new end date.
|
|
89
|
+
} else newMultiday.push(event._.id);
|
|
90
|
+
|
|
91
|
+
// @todo: handle multiday events. For now, index the event by its start date.
|
|
92
|
+
if (!newByDate[event._.startFormatted]) newByDate[event._.startFormatted] = [];
|
|
93
|
+
newByDate[event._.startFormatted].push(event._.id);
|
|
94
|
+
} else {
|
|
95
|
+
// Index this event by its start date.
|
|
96
|
+
if (!newByDate[event._.startFormatted]) newByDate[event._.startFormatted] = [];
|
|
97
|
+
newByDate[event._.startFormatted].push(event._.id);
|
|
98
|
+
|
|
99
|
+
// Index this event by its start year and month.
|
|
100
|
+
const year = event._.startFormatted.substring(0, 4);
|
|
101
|
+
const month = event._.startFormatted.substring(5, 7);
|
|
102
|
+
const day = event._.startFormatted.substring(8, 10);
|
|
103
|
+
if (!newByYear[year]) newByYear[year] = {};
|
|
104
|
+
if (!newByYear[year][month]) newByYear[year][month] = {};
|
|
105
|
+
if (!newByYear[year][month][day]) newByYear[year][month][day] = [];
|
|
106
|
+
newByYear[year][month][day].push(event._.id);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Atomic batch replacement: trigger downstream computeds only once.
|
|
111
|
+
eventsIndex.byYear = newByYear;
|
|
112
|
+
eventsIndex.byDate = newByDate;
|
|
113
|
+
eventsIndex.recurring = newRecurring;
|
|
114
|
+
eventsIndex.multiday = newMultiday;
|
|
115
|
+
eventsIndex.byId = newById;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// Normalize event dates to ensure they are valid Date objects and add formatted dates.
|
|
119
|
+
const normalizeEventDates = (event) => {
|
|
120
|
+
// Skip processing if event is invalid (will be fixed by normalizeEventDates).
|
|
121
|
+
if (!event.start || !event.end) {
|
|
122
|
+
console.error('Calendar: Event is missing start or end date', event);
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Convert string dates to Date objects if needed.
|
|
127
|
+
if (typeof event.start === 'string') event.start = dateUtils.stringToDate(event.start);
|
|
128
|
+
if (typeof event.end === 'string') event.end = dateUtils.stringToDate(event.end);
|
|
129
|
+
|
|
130
|
+
// Ensure seconds are normalized for consistent comparison.
|
|
131
|
+
event.start.setSeconds(0, 0);
|
|
132
|
+
|
|
133
|
+
// Set the event end to the next minute if the seconds count is 59.
|
|
134
|
+
if (event.end.getSeconds() === 59) event.end.setMinutes(event.end.getMinutes() + 1, 0, 0);
|
|
135
|
+
else event.end.setSeconds(0, 0); // For more accurate range and overlap comparison.
|
|
136
|
+
|
|
137
|
+
if (isNaN(event.start) || isNaN(event.end) || event.end.getTime() < event.start.getTime()) {
|
|
138
|
+
if (isNaN(event.start))
|
|
139
|
+
console.error(`Calendar: invalid start date for event "${event.title}".`, event.start);
|
|
140
|
+
else if (isNaN(event.end))
|
|
141
|
+
console.error(`Calendar: invalid end date for event "${event.title}".`, event.end);
|
|
142
|
+
else
|
|
143
|
+
console.error(
|
|
144
|
+
`Calendar: invalid event dates for event "${event.title}". The event ends before it starts.`,
|
|
145
|
+
event.start,
|
|
146
|
+
event.end,
|
|
147
|
+
);
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return true;
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
// Inject core logic and utilities in each event.
|
|
155
|
+
const injectMetaData = (event) => {
|
|
156
|
+
if (!event._) event._ = {};
|
|
157
|
+
|
|
158
|
+
// Always update these core properties as they depend on dates.
|
|
159
|
+
event._.id = event._.id || ++uid;
|
|
160
|
+
event._.multiday = !dateUtils.isSameDate(event.start, new Date(event.end.getTime() - 1)); // Remove 1ms if end is equal to next midnight.
|
|
161
|
+
event._.startFormatted = dateUtils.formatDate(event.start); // yyyy-mm-dd formatted date string.
|
|
162
|
+
event._.endFormatted = dateUtils.formatDate(event.end); // yyyy-mm-dd formatted date string.
|
|
163
|
+
event._.startMinutes = ~~dateUtils.dateToMinutes(event.start); // Integer (minutes).
|
|
164
|
+
event._.endMinutes = ~~dateUtils.dateToMinutes(event.end); // Integer (minutes).
|
|
165
|
+
const startHours = event.start.getHours();
|
|
166
|
+
const startMinutes = event.start.getMinutes().toString().padStart(2, 0);
|
|
167
|
+
const endHours = event.end.getHours();
|
|
168
|
+
const endMinutes = event.end.getMinutes().toString().padStart(2, 0);
|
|
169
|
+
event._.startTimeFormatted24 = `${startHours.toString().padStart(2, 0)}:${startMinutes}`;
|
|
170
|
+
event._.startTimeFormatted12 = `${startHours % 12 || 12}${startMinutes ? `:${startMinutes}` : ''} ${startHours < 12 ? 'AM' : 'PM'}`;
|
|
171
|
+
event._.endTimeFormatted24 = `${endHours.toString().padStart(2, 0)}:${endMinutes}`;
|
|
172
|
+
event._.endTimeFormatted12 = `${endHours % 12 || 12}${endMinutes ? `:${endMinutes}` : ''} ${endHours < 12 ? 'AM' : 'PM'}`;
|
|
173
|
+
event._.duration = Math.abs(~~((event.end - event.start) / 60000)); // Integer (minutes).
|
|
174
|
+
|
|
175
|
+
// Inject a delete function in each event and set the deleting flag to false.
|
|
176
|
+
if (!event.delete) {
|
|
177
|
+
// Use a shared function ref to avoid creating a new closure for each event.
|
|
178
|
+
event.delete = function (forcedStage) {
|
|
179
|
+
return deleteEvent(this._.id, forcedStage);
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (event._.deleting === undefined) event._.deleting = false;
|
|
184
|
+
if (event._.deleted === undefined) event._.deleted = false;
|
|
185
|
+
|
|
186
|
+
// Only inject overlap methods if they don't exist
|
|
187
|
+
if (!event.isOverlapping) {
|
|
188
|
+
/**
|
|
189
|
+
* Inject a function to check if the event is overlapping with any another event.
|
|
190
|
+
* Using shared method ref to reduce memory usage.
|
|
191
|
+
*
|
|
192
|
+
* @param {Object} at - An optional object with start and end dates to check the overlap at.
|
|
193
|
+
* If not provided, the event's own start and end dates will be used.
|
|
194
|
+
* @returns {Boolean} - True if the event is overlapping with another event.
|
|
195
|
+
*/
|
|
196
|
+
event.isOverlapping = function (at = null) {
|
|
197
|
+
return this.getOverlappingEvents(at).length;
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (!event.getOverlappingEvents) {
|
|
202
|
+
event.getOverlappingEvents = function (at = null) {
|
|
203
|
+
const eventStart = at?.start || this.start;
|
|
204
|
+
const eventEnd = at?.end || this.end;
|
|
205
|
+
const rawSchedule =
|
|
206
|
+
at?.schedule !== undefined && at?.schedule !== null ? at.schedule : this.schedule;
|
|
207
|
+
const eventSchedule = config.schedules?.length ? rawSchedule : null;
|
|
208
|
+
|
|
209
|
+
return getEventsInRange(eventStart, eventEnd, {
|
|
210
|
+
excludeIds: [this._.id],
|
|
211
|
+
schedule: eventSchedule,
|
|
212
|
+
exactTime: true,
|
|
213
|
+
});
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Only inject register/unregister methods if they don't exist
|
|
218
|
+
if (!event._.register) {
|
|
219
|
+
// Register the event DOM node in the event in order to emit DOM events.
|
|
220
|
+
// Can't use `this` and avoid new closure for each event: here it would refer to `event._`.
|
|
221
|
+
event._.register = (domNode) => {
|
|
222
|
+
event._.$el = domNode;
|
|
223
|
+
if (event._.fireCreated) {
|
|
224
|
+
calendar.emit('event-created', event);
|
|
225
|
+
delete event._.fireCreated;
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (!event._.unregister) {
|
|
231
|
+
// Unregister the event DOM node and cleanup preventing potential memory leaks.
|
|
232
|
+
// Can't use `this` and avoid new closure for each event: here it would refer to `event._`.
|
|
233
|
+
event._.unregister = () => {
|
|
234
|
+
// Only clear the DOM node reference — the event object itself may be reused
|
|
235
|
+
// in a different cell (e.g. after drag-and-drop), so utility methods like
|
|
236
|
+
// register, delete, isOverlapping, and getOverlappingEvents must remain intact.
|
|
237
|
+
event._.$el = null;
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
// Rebuild the index initially and when events are added or removed (length change).
|
|
243
|
+
// Individual event property mutations (start/end during drag/resize) do NOT trigger a rebuild —
|
|
244
|
+
// the event references in the index remain valid and the event component's own reactivity
|
|
245
|
+
// handles re-rendering at the individual event level.
|
|
246
|
+
// NOTE: watches must be placed AFTER normalizeEventDates/injectMetaData definitions
|
|
247
|
+
// to avoid temporal dead zone errors when immediate:true fires synchronously.
|
|
248
|
+
watch(
|
|
249
|
+
() => config.events.length,
|
|
250
|
+
() => buildEventsIndex(),
|
|
251
|
+
{ immediate: true },
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
// Also handle full array reference replacement (e.g., props.events replaced entirely).
|
|
255
|
+
watch(
|
|
256
|
+
() => config.events,
|
|
257
|
+
() => buildEventsIndex(),
|
|
258
|
+
{ deep: false },
|
|
259
|
+
);
|
|
260
|
+
|
|
261
|
+
// Retrieve an event by its ID.
|
|
262
|
+
const getEvent = (id) => eventsIndex.byId[id];
|
|
263
|
+
|
|
264
|
+
// Get events for the view based on cell dates.
|
|
265
|
+
// Returns an object of cell events arrays indexed by the cell string date.
|
|
266
|
+
const getViewEvents = (cellDates) => {
|
|
267
|
+
const events = [];
|
|
268
|
+
for (const { start, end } of cellDates) {
|
|
269
|
+
const eventsByDate = getEventsInRange(start, end);
|
|
270
|
+
if (eventsByDate.length) events.push(...eventsByDate);
|
|
271
|
+
}
|
|
272
|
+
return events;
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
// Create a new event and add it to the events list.
|
|
276
|
+
const createEvent = (newEvent) => {
|
|
277
|
+
if (!newEvent.start || !newEvent.end) {
|
|
278
|
+
console.error('Calendar: Cannot create an event without valid start and end dates.');
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// If `snapToInterval` is enabled in the configuration, adjust the `start` and `end` times to the
|
|
283
|
+
// nearest interval specified by `config.snapToInterval`.
|
|
284
|
+
if (config.snapToInterval) {
|
|
285
|
+
dateUtils.snapToInterval(newEvent.start, config.snapToInterval);
|
|
286
|
+
dateUtils.snapToInterval(newEvent.end, config.snapToInterval);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Create a clean deep copy of the event to prevent reference issues.
|
|
290
|
+
newEvent = { ...newEvent };
|
|
291
|
+
|
|
292
|
+
const start =
|
|
293
|
+
typeof newEvent.start === 'string'
|
|
294
|
+
? dateUtils.stringToDate(newEvent.start)
|
|
295
|
+
: new Date(newEvent.start);
|
|
296
|
+
const end =
|
|
297
|
+
typeof newEvent.end === 'string'
|
|
298
|
+
? dateUtils.stringToDate(newEvent.end)
|
|
299
|
+
: new Date(newEvent.end);
|
|
300
|
+
if (
|
|
301
|
+
!newEvent.allDay &&
|
|
302
|
+
config.time &&
|
|
303
|
+
config.specialHoursDisallowed?.hasAny &&
|
|
304
|
+
eventRangeViolatesAllowEvents({
|
|
305
|
+
start,
|
|
306
|
+
end,
|
|
307
|
+
schedule: newEvent.schedule,
|
|
308
|
+
disallowed: config.specialHoursDisallowed,
|
|
309
|
+
hasSchedules: !!(config.schedules && config.schedules.length),
|
|
310
|
+
})
|
|
311
|
+
) {
|
|
312
|
+
console.warn(
|
|
313
|
+
'Calendar: Cannot create an event overlapping a time range where allowEvents is false.',
|
|
314
|
+
);
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
newEvent.start = start;
|
|
318
|
+
newEvent.end = end;
|
|
319
|
+
|
|
320
|
+
// Always override any existing ID when created: it could come from an external source
|
|
321
|
+
// with an existing _.id, but we need to ensure it's unique for internal management.
|
|
322
|
+
if (!newEvent._) newEvent._ = {};
|
|
323
|
+
newEvent._.id = ++uid;
|
|
324
|
+
|
|
325
|
+
newEvent._.fireCreated = true; // Flag to fire the 'event-created' event on first mounted.
|
|
326
|
+
config.events.push(newEvent); // Add the new event to the source of truth.
|
|
327
|
+
return newEvent;
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Deletes an event based on the provided eventId or criteria and forcedStage.
|
|
332
|
+
*
|
|
333
|
+
* @param {string|number|Object} eventIdOrCriteria - The ID of the event to delete or an object with criteria to find the event.
|
|
334
|
+
* @param {number} [forcedStage=0] - The stage of deletion to force.
|
|
335
|
+
* 0: Initial deletion stage, toggles deleting and deleted flags.
|
|
336
|
+
* 1: Sets the deleting flag to true.
|
|
337
|
+
* 2: Sets the deleted flag to true and dispatches 'event-deleted' event.
|
|
338
|
+
* 3: Removes the event from the source of truth, emits 'update:events' and 'event-delete' events, and dispatches 'event-deleted' event.
|
|
339
|
+
* @returns {boolean} - Returns true for chaining.
|
|
340
|
+
*/
|
|
341
|
+
const deleteEvent = async (eventIdOrCriteria, forcedStage = 0) => {
|
|
342
|
+
if (!eventIdOrCriteria)
|
|
343
|
+
return console.warn('Calendar: Cannot delete event without its ID or criteria.');
|
|
344
|
+
let eventId =
|
|
345
|
+
typeof eventIdOrCriteria === 'string' || !isNaN(eventIdOrCriteria) ? eventIdOrCriteria : null;
|
|
346
|
+
const eventCriteria =
|
|
347
|
+
typeof eventIdOrCriteria === 'object' ? Object.entries(eventIdOrCriteria) : null;
|
|
348
|
+
if (eventCriteria) {
|
|
349
|
+
const [criteriaKey, criteriaValue] = eventCriteria[0];
|
|
350
|
+
eventId = config.events.find((event) => event[criteriaKey] === criteriaValue)?._.id;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (!config.editableEvents.delete) {
|
|
354
|
+
return console.info(
|
|
355
|
+
'Calendar: Event deletion is disabled. Enable it with the `editable-events` props.',
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
if (!eventId) return console.warn('Calendar: Cannot delete event without its ID.');
|
|
359
|
+
|
|
360
|
+
const index = config.events.findIndex((item) => item._.id === eventId);
|
|
361
|
+
if (index === -1) return console.warn(`Calendar: Cannot delete unknown event \`${eventId}\`.`);
|
|
362
|
+
|
|
363
|
+
const event = config.events[index];
|
|
364
|
+
if (event.deletable === false)
|
|
365
|
+
return console.warn(
|
|
366
|
+
`Calendar: Can't delete event \`${eventId}\` since it was explicitely set to \`delete: false\`.`,
|
|
367
|
+
);
|
|
368
|
+
|
|
369
|
+
switch (forcedStage) {
|
|
370
|
+
case 0:
|
|
371
|
+
if (!event._.deleting) event._.deleting = true;
|
|
372
|
+
// If the event is already marked as deleting, delete completely from the source of truth
|
|
373
|
+
// by default, and skip the stage 2. Stage 2 (for visual deletion) will stay on specific demand.
|
|
374
|
+
else config.events.splice(index, 1); // Remove the event from the source of truth.
|
|
375
|
+
break;
|
|
376
|
+
// Display the delete button.
|
|
377
|
+
case 1:
|
|
378
|
+
event._.deleting = true;
|
|
379
|
+
break;
|
|
380
|
+
// Visual deletion + external DOM event firing.
|
|
381
|
+
// When explicitly using this stage, the event will be visually deleted but still present in the
|
|
382
|
+
// source of truth until the cell is unmounted (by navigating away).
|
|
383
|
+
case 2:
|
|
384
|
+
event._.deleted = true;
|
|
385
|
+
config.events[index]._.deleted = true;
|
|
386
|
+
// Internal emit to the cell (`detail` is the native expected object wrapper).
|
|
387
|
+
event._.$el?.dispatchEvent(new CustomEvent('event-deleted', { detail: event._.id }));
|
|
388
|
+
break;
|
|
389
|
+
// Effective deletion from the source of truth (by default, when unmounting the cell).
|
|
390
|
+
case 3:
|
|
391
|
+
// Removing the event from the source of truth causes a reactivity update cascade that rerenders
|
|
392
|
+
// all the cells and sub-components. This is not a bug, but in most cases, not the ideal behavior.
|
|
393
|
+
config.events.splice(index, 1); // Remove the event from the source of truth.
|
|
394
|
+
calendar.emit('update:events', config.events);
|
|
395
|
+
calendar.emit('event-delete', event);
|
|
396
|
+
break;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
return true; // For chaining.
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
// Will recalculate all the overlaps of the current cell OR schedule.
|
|
403
|
+
// cellEvents will contain only the current schedule events if in a schedule.
|
|
404
|
+
const getCellOverlappingEvents = (cellStart, cellEnd, allDay) => {
|
|
405
|
+
const allDayFilter = config.allDayEvents ? { allDay } : {};
|
|
406
|
+
const cellEvents = getEventsInRange(cellStart, cellEnd, { background: false, ...allDayFilter });
|
|
407
|
+
if (!cellEvents.length) return { cellOverlaps: {}, longestStreak: 0 };
|
|
408
|
+
|
|
409
|
+
const cellOverlaps = {};
|
|
410
|
+
let activeEvents = [];
|
|
411
|
+
// Overlaps streak is the longest horizontal set of simultaneous events.
|
|
412
|
+
// This is determining the width of events in a streak.
|
|
413
|
+
// e.g. 3 overlapping events in a cell:
|
|
414
|
+
// ___ ___
|
|
415
|
+
// | 1 | |_2_| 1 overlaps 2 & 3; 2 & 3 don't overlap;
|
|
416
|
+
// | | ___ => streak = 2; each width = 50% not 33%.
|
|
417
|
+
// |___| |_3_|
|
|
418
|
+
let maxConcurrent = 0;
|
|
419
|
+
|
|
420
|
+
// Sort events by start time, then by duration (shorter first).
|
|
421
|
+
cellEvents.sort((a, b) => a.start - b.start || a.end - a.start - (b.end - b.start));
|
|
422
|
+
|
|
423
|
+
for (const e of cellEvents) {
|
|
424
|
+
const id = e._.id;
|
|
425
|
+
|
|
426
|
+
if (!cellOverlaps[id])
|
|
427
|
+
cellOverlaps[id] = { overlaps: new Set(), maxConcurrent: 1, position: 0 };
|
|
428
|
+
|
|
429
|
+
// Remove expired events from active tracking list.
|
|
430
|
+
activeEvents = activeEvents.filter((active) => active.end > e.start);
|
|
431
|
+
|
|
432
|
+
// Find all current overlaps in the current cell or schedule.
|
|
433
|
+
const currentOverlaps = activeEvents.filter((active) => {
|
|
434
|
+
const sameSchedule = !config.schedules?.length || e.schedule === active.schedule;
|
|
435
|
+
return sameSchedule && active.start < e.end;
|
|
436
|
+
});
|
|
437
|
+
const takenPositions = new Set(
|
|
438
|
+
currentOverlaps.map((ev) => cellOverlaps[ev._.id]?.position ?? 0),
|
|
439
|
+
);
|
|
440
|
+
|
|
441
|
+
// Assign the lowest available column position.
|
|
442
|
+
let position = 0;
|
|
443
|
+
while (takenPositions.has(position)) position++;
|
|
444
|
+
|
|
445
|
+
cellOverlaps[id].position = position;
|
|
446
|
+
activeEvents.push(e);
|
|
447
|
+
|
|
448
|
+
// Calculate inherited maxConcurrent from overlaps.
|
|
449
|
+
const inheritedMax = Math.max(
|
|
450
|
+
1,
|
|
451
|
+
...currentOverlaps.map((ev) => cellOverlaps[ev._.id]?.maxConcurrent ?? 1),
|
|
452
|
+
);
|
|
453
|
+
|
|
454
|
+
// Set maxConcurrent for this event.
|
|
455
|
+
cellOverlaps[id].maxConcurrent = Math.max(currentOverlaps.length + 1, inheritedMax);
|
|
456
|
+
|
|
457
|
+
// Update all overlapping events to match the new maxConcurrent.
|
|
458
|
+
for (const activeEvent of currentOverlaps) {
|
|
459
|
+
cellOverlaps[activeEvent._.id].overlaps.add(id);
|
|
460
|
+
cellOverlaps[id].overlaps.add(activeEvent._.id);
|
|
461
|
+
cellOverlaps[activeEvent._.id].maxConcurrent = cellOverlaps[id].maxConcurrent;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// Track the longest streak of overlapping events.
|
|
465
|
+
maxConcurrent = Math.max(maxConcurrent, cellOverlaps[id].maxConcurrent);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// Convert Sets to Arrays.
|
|
469
|
+
for (const id in cellOverlaps) cellOverlaps[id].overlaps = [...cellOverlaps[id].overlaps];
|
|
470
|
+
|
|
471
|
+
return { cellOverlaps, longestStreak: maxConcurrent };
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* Returns a list of events that are in the provided date range.
|
|
476
|
+
* Optionally exclude some events by their IDs and optionally filter by schedule.
|
|
477
|
+
* Optimized implementation that avoids unnecessary computations.
|
|
478
|
+
*
|
|
479
|
+
* @param {Date} start Start date of the range
|
|
480
|
+
* @param {Date} end End date of the range
|
|
481
|
+
* @param {Object} options Additional options for filtering
|
|
482
|
+
* options.excludeIds An array of event IDs to exclude from the results.
|
|
483
|
+
* options.schedule The schedule to filter events by.
|
|
484
|
+
* options.background Whether to include background events.
|
|
485
|
+
* options.allDay Whether to include all-day events.
|
|
486
|
+
* options.exactTime Whether to use precise timestamps for overlap checks.
|
|
487
|
+
* @returns {Array} Array of events in the range
|
|
488
|
+
*/
|
|
489
|
+
const getEventsInRange = (
|
|
490
|
+
start,
|
|
491
|
+
end,
|
|
492
|
+
{ excludeIds = [], schedule = null, background = true, allDay = false, exactTime = false } = {},
|
|
493
|
+
) => {
|
|
494
|
+
const { byId, byYear } = eventsIndex;
|
|
495
|
+
const totalEvents = Object.keys(byId).length;
|
|
496
|
+
|
|
497
|
+
// Fast path: if there are no events, return empty array immediately.
|
|
498
|
+
if (!totalEvents) return [];
|
|
499
|
+
|
|
500
|
+
const startYear = start.getFullYear();
|
|
501
|
+
const endYear = end.getFullYear();
|
|
502
|
+
const startMonth = start.getMonth() + 1;
|
|
503
|
+
const endMonth = end.getMonth() + 1;
|
|
504
|
+
const startDay = start.getDate();
|
|
505
|
+
const endDay = end.getDate();
|
|
506
|
+
// exactTime: use precise timestamps (for overlap checks); otherwise normalize to day boundaries
|
|
507
|
+
// (for view/cell range queries where any event on the date should be included).
|
|
508
|
+
const rangeStartTimestamp = exactTime ? start.getTime() : new Date(start).setHours(0, 0, 0, 0);
|
|
509
|
+
const rangeEndTimestamp = exactTime ? end.getTime() : new Date(end).setHours(23, 59, 59, 999);
|
|
510
|
+
|
|
511
|
+
const excludeSet = new Set(excludeIds);
|
|
512
|
+
const eventsArray = [];
|
|
513
|
+
|
|
514
|
+
// If there are less than 100 events, we can use a simple loop to find events in the range.
|
|
515
|
+
if (totalEvents <= 100) {
|
|
516
|
+
for (const event of Object.values(byId)) {
|
|
517
|
+
if (!event || excludeSet.has(event._.id)) continue;
|
|
518
|
+
if (schedule !== null && schedule !== event.schedule) continue;
|
|
519
|
+
if (background === false && event.background) continue;
|
|
520
|
+
if (config.allDayEvents && ((allDay && !event.allDay) || (!allDay && event.allDay)))
|
|
521
|
+
continue;
|
|
522
|
+
// Accept events that overlap the range.
|
|
523
|
+
if (event.start.getTime() < rangeEndTimestamp && event.end.getTime() > rangeStartTimestamp)
|
|
524
|
+
eventsArray.push(event);
|
|
525
|
+
}
|
|
526
|
+
return eventsArray;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// If there are more than 100 events, we need to use a more efficient approach.
|
|
530
|
+
// We'll use the byYear index to find events in the range.
|
|
531
|
+
for (let year = startYear; year <= endYear; year++) {
|
|
532
|
+
const yearStr = `${year}`;
|
|
533
|
+
const months = byYear[yearStr];
|
|
534
|
+
if (!months) continue;
|
|
535
|
+
|
|
536
|
+
const monthFrom = year === startYear ? startMonth : 1;
|
|
537
|
+
const monthTo = year === endYear ? endMonth : 12;
|
|
538
|
+
|
|
539
|
+
for (let month = monthFrom; month <= monthTo; month++) {
|
|
540
|
+
const monthStr = String(month).padStart(2, '0');
|
|
541
|
+
const days = months[monthStr];
|
|
542
|
+
if (!days) continue;
|
|
543
|
+
|
|
544
|
+
for (const dayStr in days) {
|
|
545
|
+
const day = +dayStr;
|
|
546
|
+
// Only skip days outside the range at the boundary months/years to avoid false
|
|
547
|
+
// positives when the range crosses month or year boundaries.
|
|
548
|
+
if (year === startYear && month === startMonth && day < startDay) continue;
|
|
549
|
+
if (year === endYear && month === endMonth && day > endDay) continue;
|
|
550
|
+
|
|
551
|
+
const dayEventIds = days[dayStr];
|
|
552
|
+
if (!dayEventIds?.length) continue;
|
|
553
|
+
|
|
554
|
+
// Process events in this day in bulk.
|
|
555
|
+
for (let i = 0; i < dayEventIds.length; i++) {
|
|
556
|
+
const e = byId[dayEventIds[i]];
|
|
557
|
+
if (!e || excludeSet.has(e._.id)) continue;
|
|
558
|
+
if (schedule !== null && schedule !== e.schedule) continue;
|
|
559
|
+
if (background === false && e.background) continue;
|
|
560
|
+
if (config.allDayEvents && ((allDay && !e.allDay) || (!allDay && e.allDay))) continue;
|
|
561
|
+
// Accept events that overlap the range.
|
|
562
|
+
if (e.start.getTime() < rangeEndTimestamp && e.end.getTime() > rangeStartTimestamp)
|
|
563
|
+
eventsArray.push(e);
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
return eventsArray;
|
|
570
|
+
};
|
|
571
|
+
|
|
572
|
+
/**
|
|
573
|
+
* Returns true if an event is in a given date range, even partially, or false otherwise.
|
|
574
|
+
*
|
|
575
|
+
* @param {Object} event The event to test.
|
|
576
|
+
* @param {Date} start The start of range date object.
|
|
577
|
+
* @param {Date} end The end of range date object.
|
|
578
|
+
* @return {Boolean} true if in range, even partially.
|
|
579
|
+
*/
|
|
580
|
+
const isEventInRange = (event, start, end) => {
|
|
581
|
+
// Check if all-day or timeless event (if date but no time there won't be a `:` in event.start),
|
|
582
|
+
// and discard the time from the date if any,
|
|
583
|
+
const allDayOrTimeless = event.allDay || !config.time;
|
|
584
|
+
|
|
585
|
+
const startTimestamp = allDayOrTimeless
|
|
586
|
+
? new Date(event.start).setHours(0, 0, 0, 0)
|
|
587
|
+
: event.start.getTime();
|
|
588
|
+
const endTimestamp = allDayOrTimeless
|
|
589
|
+
? new Date(event.end).setHours(23, 59, 59, 999)
|
|
590
|
+
: event.end.getTime();
|
|
591
|
+
const rangeStart = allDayOrTimeless ? new Date(start).setHours(0, 0, 0, 0) : start.getTime();
|
|
592
|
+
const rangeEnd = allDayOrTimeless ? new Date(end).setHours(23, 59, 59, 999) : end.getTime();
|
|
593
|
+
// Check the event is within the range, considering at least one second overlap.
|
|
594
|
+
return endTimestamp > rangeStart && startTimestamp < rangeEnd;
|
|
595
|
+
};
|
|
596
|
+
|
|
597
|
+
// Resizing state management.
|
|
598
|
+
const resizeState = reactive({
|
|
599
|
+
isResizing: false,
|
|
600
|
+
fromResizer: false,
|
|
601
|
+
resizingEvent: null,
|
|
602
|
+
resizingOriginalEvent: null,
|
|
603
|
+
resizingLastAcceptedEvent: null,
|
|
604
|
+
startX: 0,
|
|
605
|
+
startY: 0,
|
|
606
|
+
startPercentageX: 0,
|
|
607
|
+
startPercentageY: 0,
|
|
608
|
+
moveX: 0,
|
|
609
|
+
moveY: 0,
|
|
610
|
+
movePercentageX: 0,
|
|
611
|
+
movePercentageY: 0,
|
|
612
|
+
documentMouseX: 0,
|
|
613
|
+
documentMouseY: 0,
|
|
614
|
+
resizeStartDate: null,
|
|
615
|
+
resizeBaselineEndMs: null,
|
|
616
|
+
cellEl: null,
|
|
617
|
+
schedule: null,
|
|
618
|
+
resizeAnchorClientX: 0,
|
|
619
|
+
resizeAnchorClientY: 0,
|
|
620
|
+
resizeSlopExceeded: false,
|
|
621
|
+
});
|
|
622
|
+
|
|
623
|
+
/**
|
|
624
|
+
* Compute the new start and end of the event based on the touch move percentage while resizing.
|
|
625
|
+
* @param {Object} event - The event object.
|
|
626
|
+
* @param {Object} cellStart - The cell start date.
|
|
627
|
+
* @returns {Object} - The new start and end of the event.
|
|
628
|
+
*/
|
|
629
|
+
const computeEventStartEnd = (event, cellStart) => {
|
|
630
|
+
// Use X percentage for horizontal layout, Y for vertical.
|
|
631
|
+
const movePercentage = resizeState[config.horizontal ? 'movePercentageX' : 'movePercentageY'];
|
|
632
|
+
let minutes = percentageToMinutes(movePercentage, config);
|
|
633
|
+
|
|
634
|
+
// While resizing, cap the newEnd between the previous midnight and next midnight.
|
|
635
|
+
minutes = Math.max(0, Math.min(minutes, 24 * 60));
|
|
636
|
+
|
|
637
|
+
// On drop, snap to time every X minutes if the option is on.
|
|
638
|
+
if (config.snapToInterval) {
|
|
639
|
+
const plusHalfSnapTime = minutes + config.snapToInterval / 2;
|
|
640
|
+
minutes = plusHalfSnapTime - (plusHalfSnapTime % config.snapToInterval);
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
let newStart = event.start;
|
|
644
|
+
let newEnd = new Date(cellStart.getTime() + minutes * 60000);
|
|
645
|
+
|
|
646
|
+
// If the event is resizing horizontally by the user dragging and crossing a cell,
|
|
647
|
+
// Set the end date to the hovered cell's start date while preserving the time at cursor position.
|
|
648
|
+
if (resizeState.moveX && calendar.touch?.currentHoveredCell && resizeState.cellEl) {
|
|
649
|
+
// Get the current hovered cell date from global touch state.
|
|
650
|
+
const currentCellDate = new Date(parseInt(calendar.touch.currentHoveredCell.dataset.start));
|
|
651
|
+
|
|
652
|
+
// Set the event end date to the hovered cell's date.
|
|
653
|
+
// newEnd.setDate(currentCellDate.getDate())
|
|
654
|
+
// newEnd.setMonth(currentCellDate.getMonth())
|
|
655
|
+
// newEnd.setYear(currentCellDate.getFullYear())
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
// While resizing and event end is before event start.
|
|
659
|
+
if (newEnd < resizeState.resizeStartDate) {
|
|
660
|
+
newStart = newEnd;
|
|
661
|
+
newEnd = resizeState.resizeStartDate;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
return { newStart, newEnd };
|
|
665
|
+
};
|
|
666
|
+
|
|
667
|
+
const RESIZE_SLOP_SQ = 4; // 2px; ignore jitter until pointer moves farther than this from mousedown.
|
|
668
|
+
|
|
669
|
+
const syncResizePointerFromClient = (clientX, clientY) => {
|
|
670
|
+
if (!resizeState.cellEl) return;
|
|
671
|
+
const { top, left, width, height } = resizeState.cellEl.getBoundingClientRect();
|
|
672
|
+
resizeState.moveX = clientX - left;
|
|
673
|
+
resizeState.moveY = clientY - top;
|
|
674
|
+
resizeState.movePercentageX = (resizeState.moveX * 100) / width;
|
|
675
|
+
resizeState.movePercentageY = (resizeState.moveY * 100) / height;
|
|
676
|
+
resizeState.documentMouseX = clientX;
|
|
677
|
+
resizeState.documentMouseY = clientY;
|
|
678
|
+
};
|
|
679
|
+
|
|
680
|
+
const getClampedResizeProposal = (ev, cellStart) => {
|
|
681
|
+
const prevStart = new Date(ev.start);
|
|
682
|
+
const prevEnd = new Date(ev.end);
|
|
683
|
+
let { newStart, newEnd } = computeEventStartEnd(ev, cellStart);
|
|
684
|
+
|
|
685
|
+
if (config.time && !ev.allDay && config.specialHoursDisallowed?.hasAny) {
|
|
686
|
+
const clamped = clampResizeProposedRange({
|
|
687
|
+
proposedStart: newStart,
|
|
688
|
+
proposedEnd: newEnd,
|
|
689
|
+
prevStart,
|
|
690
|
+
prevEnd,
|
|
691
|
+
schedule: ev.schedule,
|
|
692
|
+
disallowed: config.specialHoursDisallowed,
|
|
693
|
+
hasSchedules: !!(config.schedules && config.schedules.length),
|
|
694
|
+
});
|
|
695
|
+
newStart = clamped.start;
|
|
696
|
+
newEnd = clamped.end;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
const internalOk =
|
|
700
|
+
!config.time ||
|
|
701
|
+
ev.allDay ||
|
|
702
|
+
!config.specialHoursDisallowed?.hasAny ||
|
|
703
|
+
!eventRangeViolatesAllowEvents({
|
|
704
|
+
start: newStart,
|
|
705
|
+
end: newEnd,
|
|
706
|
+
schedule: ev.schedule,
|
|
707
|
+
disallowed: config.specialHoursDisallowed,
|
|
708
|
+
hasSchedules: !!(config.schedules && config.schedules.length),
|
|
709
|
+
});
|
|
710
|
+
|
|
711
|
+
return { newStart, newEnd, internalOk };
|
|
712
|
+
};
|
|
713
|
+
|
|
714
|
+
// Document event handlers for event resizing.
|
|
715
|
+
const onDocumentMousemove = async (e) => {
|
|
716
|
+
const { clientX, clientY } = e.touches?.[0] || e; // Handle click or touch event.
|
|
717
|
+
|
|
718
|
+
const adx = clientX - resizeState.resizeAnchorClientX;
|
|
719
|
+
const ady = clientY - resizeState.resizeAnchorClientY;
|
|
720
|
+
if (!resizeState.resizeSlopExceeded) {
|
|
721
|
+
if (adx * adx + ady * ady <= RESIZE_SLOP_SQ) return;
|
|
722
|
+
resizeState.resizeSlopExceeded = true;
|
|
723
|
+
}
|
|
724
|
+
syncResizePointerFromClient(clientX, clientY);
|
|
725
|
+
|
|
726
|
+
// Only the first committed move stores original event and fires resize-start.
|
|
727
|
+
if (resizeState.fromResizer && !resizeState.resizingOriginalEvent) {
|
|
728
|
+
resizeState.resizingOriginalEvent = {
|
|
729
|
+
...resizeState.resizingEvent,
|
|
730
|
+
_: { ...resizeState.resizingEvent._ },
|
|
731
|
+
};
|
|
732
|
+
|
|
733
|
+
// If there's an @event-resize-start external listener, call it.
|
|
734
|
+
const eventListeners = config.eventListeners?.event || {};
|
|
735
|
+
eventListeners['resize-start']?.({ e, event: resizeState.resizingEvent });
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
if (resizeState.fromResizer && resizeState.resizingEvent) {
|
|
739
|
+
const cellStart = new Date(parseInt(resizeState.cellEl.dataset.start));
|
|
740
|
+
const { newStart, newEnd, internalOk } = getClampedResizeProposal(
|
|
741
|
+
resizeState.resizingEvent,
|
|
742
|
+
cellStart,
|
|
743
|
+
);
|
|
744
|
+
|
|
745
|
+
// If there's an @event-resize external listener, call it and ask for resizing approval.
|
|
746
|
+
let acceptResize = internalOk;
|
|
747
|
+
const { resize: resizeEventHandler } = config.eventListeners?.event || {};
|
|
748
|
+
// Call external validation of event resizing. If successful, update the event details.
|
|
749
|
+
if (internalOk && resizeEventHandler) {
|
|
750
|
+
acceptResize = await resizeEventHandler({
|
|
751
|
+
e,
|
|
752
|
+
event: { ...resizeState.resizingEvent, start: newStart, end: newEnd },
|
|
753
|
+
overlaps: resizeState.resizingEvent.getOverlappingEvents({
|
|
754
|
+
start: newStart,
|
|
755
|
+
end: newEnd,
|
|
756
|
+
}),
|
|
757
|
+
});
|
|
758
|
+
}
|
|
759
|
+
// If the event resizing is accepted, apply to new time range to the event.
|
|
760
|
+
if (acceptResize !== false) {
|
|
761
|
+
resizeState.resizingEvent.start = newStart;
|
|
762
|
+
resizeState.resizingEvent.end = newEnd;
|
|
763
|
+
// Update event metadata in-place so the event component renders with correct position.
|
|
764
|
+
injectMetaData(resizeState.resizingEvent);
|
|
765
|
+
// Reset last accepted event details if existing and accepting again.
|
|
766
|
+
if (resizeState.resizingLastAcceptedEvent) resizeState.resizingLastAcceptedEvent = null;
|
|
767
|
+
|
|
768
|
+
// Prevent scrolling while resizing.
|
|
769
|
+
// Can only be done when event handler is not passive.
|
|
770
|
+
e.preventDefault();
|
|
771
|
+
} else {
|
|
772
|
+
// If the event resizing is refused, store the last accepted original event details
|
|
773
|
+
// so it can be used to revert to this stage on event-resize-end (in `onDocumentMouseup`).
|
|
774
|
+
if (resizeEventHandler)
|
|
775
|
+
resizeState.resizingLastAcceptedEvent = {
|
|
776
|
+
...resizeState.resizingEvent,
|
|
777
|
+
_: { ...resizeState.resizingEvent._ },
|
|
778
|
+
};
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
};
|
|
782
|
+
|
|
783
|
+
const onDocumentMouseup = async (e) => {
|
|
784
|
+
if (calendar.touch?.isResizingEvent && resizeState.resizingEvent) {
|
|
785
|
+
const { clientX, clientY } = e.changedTouches?.[0] || e;
|
|
786
|
+
if (!resizeState.resizeSlopExceeded) {
|
|
787
|
+
resizeState.resizingEvent.start = new Date(resizeState.resizeStartDate);
|
|
788
|
+
resizeState.resizingEvent.end = new Date(resizeState.resizeBaselineEndMs);
|
|
789
|
+
} else {
|
|
790
|
+
syncResizePointerFromClient(clientX, clientY);
|
|
791
|
+
const cellStart = new Date(parseInt(resizeState.cellEl.dataset.start));
|
|
792
|
+
const { newStart, newEnd, internalOk } = getClampedResizeProposal(
|
|
793
|
+
resizeState.resizingEvent,
|
|
794
|
+
cellStart,
|
|
795
|
+
);
|
|
796
|
+
|
|
797
|
+
// If there's an @event-resize-end external listener, call it.
|
|
798
|
+
let acceptResize = internalOk;
|
|
799
|
+
const eventListeners = config.eventListeners?.event || {};
|
|
800
|
+
const resizeEndHandler = eventListeners['resize-end'];
|
|
801
|
+
// Call external validation of event resize-end. If successful, update the event details.
|
|
802
|
+
if (internalOk && resizeEndHandler) {
|
|
803
|
+
acceptResize = await resizeEndHandler({
|
|
804
|
+
e,
|
|
805
|
+
event: resizeState.resizingEvent,
|
|
806
|
+
original: resizeState.resizingOriginalEvent, // Original event details before resizing.
|
|
807
|
+
overlaps: resizeState.resizingEvent.getOverlappingEvents({
|
|
808
|
+
start: newStart,
|
|
809
|
+
end: newEnd,
|
|
810
|
+
}),
|
|
811
|
+
});
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
// If the event resize is accepted apply new range, if refused (SPECIFICALLY FALSE) revert to original.
|
|
815
|
+
resizeState.resizingEvent.start =
|
|
816
|
+
acceptResize === false
|
|
817
|
+
? (resizeState.resizingLastAcceptedEvent || resizeState.resizingOriginalEvent).start
|
|
818
|
+
: resizeState.resizingLastAcceptedEvent?.start || newStart;
|
|
819
|
+
resizeState.resizingEvent.end =
|
|
820
|
+
acceptResize === false
|
|
821
|
+
? (resizeState.resizingLastAcceptedEvent || resizeState.resizingOriginalEvent).end
|
|
822
|
+
: resizeState.resizingLastAcceptedEvent?.end || newEnd;
|
|
823
|
+
// If resizing to less than 1 minute, revert to original.
|
|
824
|
+
if (resizeState.resizingEvent._.duration < 1 && resizeState.resizingOriginalEvent) {
|
|
825
|
+
resizeState.resizingEvent.start = resizeState.resizingOriginalEvent.start;
|
|
826
|
+
resizeState.resizingEvent.end = resizeState.resizingOriginalEvent.end;
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
// Refresh event metadata so the index and display reflect the final position.
|
|
830
|
+
injectMetaData(resizeState.resizingEvent);
|
|
831
|
+
calendar.touch.isResizingEvent = false; // Add a CSS class on wrapper while resizing.
|
|
832
|
+
calendar.touch.currentHoveredCell = null; // Reset current hovered cell.
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
// Clean up document event listeners.
|
|
836
|
+
document.removeEventListener(
|
|
837
|
+
e.type === 'touchend' ? 'touchmove' : 'mousemove',
|
|
838
|
+
onDocumentMousemove,
|
|
839
|
+
{ passive: !resizeState.fromResizer },
|
|
840
|
+
);
|
|
841
|
+
|
|
842
|
+
// Reset resizing state.
|
|
843
|
+
calendar.touch.isResizingEvent = false;
|
|
844
|
+
resizeState.fromResizer = false;
|
|
845
|
+
resizeState.resizingEvent = null;
|
|
846
|
+
resizeState.resizingOriginalEvent = null;
|
|
847
|
+
resizeState.resizingLastAcceptedEvent = null;
|
|
848
|
+
resizeState.startX = 0;
|
|
849
|
+
resizeState.startY = 0;
|
|
850
|
+
resizeState.moveX = 0;
|
|
851
|
+
resizeState.moveY = 0;
|
|
852
|
+
resizeState.startPercentageX = 0;
|
|
853
|
+
resizeState.startPercentageY = 0;
|
|
854
|
+
resizeState.movePercentageX = 0;
|
|
855
|
+
resizeState.movePercentageY = 0;
|
|
856
|
+
resizeState.documentMouseX = 0;
|
|
857
|
+
resizeState.documentMouseY = 0;
|
|
858
|
+
resizeState.cellEl = null;
|
|
859
|
+
resizeState.resizeStartDate = null;
|
|
860
|
+
resizeState.resizeBaselineEndMs = null;
|
|
861
|
+
resizeState.schedule = null;
|
|
862
|
+
resizeState.resizeAnchorClientX = 0;
|
|
863
|
+
resizeState.resizeAnchorClientY = 0;
|
|
864
|
+
resizeState.resizeSlopExceeded = false;
|
|
865
|
+
};
|
|
866
|
+
|
|
867
|
+
// Handle mousedown/touchstart on event elements
|
|
868
|
+
const handleEventResize = (e, event, eventEl) => {
|
|
869
|
+
const domEvent = e.touches?.[0] || e; // Handle click or touch event.
|
|
870
|
+
// If the event target is the resizer, set the resizing flag.
|
|
871
|
+
resizeState.fromResizer = !!domEvent.target.closest(`.${prefixCls}__event-resizer`);
|
|
872
|
+
|
|
873
|
+
if (resizeState.fromResizer) {
|
|
874
|
+
// Set the resizing flag immediately to prevent drag from starting.
|
|
875
|
+
calendar.touch.isResizingEvent = true;
|
|
876
|
+
|
|
877
|
+
const rect = eventEl.getBoundingClientRect();
|
|
878
|
+
resizeState.startX = domEvent.clientX - rect.left; // Handle click or touch event coords.
|
|
879
|
+
resizeState.startY = domEvent.clientY - rect.top; // Handle click or touch event coords.
|
|
880
|
+
resizeState.startPercentageX = (resizeState.startX * 100) / rect.width;
|
|
881
|
+
resizeState.startPercentageY = (resizeState.startY * 100) / rect.height;
|
|
882
|
+
// Store the cell DOM node for a more efficient resizing calc in mousemove/touchmove.
|
|
883
|
+
resizeState.cellEl = eventEl.closest(`.${prefixCls}__cell`);
|
|
884
|
+
// Immutable gesture start (swap logic + cancel if no real drag).
|
|
885
|
+
resizeState.resizeStartDate = new Date(event.start.getTime());
|
|
886
|
+
resizeState.resizeBaselineEndMs = event.end.getTime();
|
|
887
|
+
// Store the event being resized.
|
|
888
|
+
resizeState.resizingEvent = event;
|
|
889
|
+
resizeState.resizeAnchorClientX = domEvent.clientX;
|
|
890
|
+
resizeState.resizeAnchorClientY = domEvent.clientY;
|
|
891
|
+
resizeState.resizeSlopExceeded = false;
|
|
892
|
+
|
|
893
|
+
// Make the event listener non-passive if resizing so we can prevent default scrolling.
|
|
894
|
+
document.addEventListener(
|
|
895
|
+
e.type === 'touchstart' ? 'touchmove' : 'mousemove',
|
|
896
|
+
onDocumentMousemove,
|
|
897
|
+
{ passive: !resizeState.fromResizer },
|
|
898
|
+
);
|
|
899
|
+
document.addEventListener(
|
|
900
|
+
e.type === 'touchstart' ? 'touchend' : 'mouseup',
|
|
901
|
+
onDocumentMouseup,
|
|
902
|
+
{ once: true },
|
|
903
|
+
);
|
|
904
|
+
}
|
|
905
|
+
};
|
|
906
|
+
|
|
907
|
+
return {
|
|
908
|
+
eventsIndex,
|
|
909
|
+
resizeState,
|
|
910
|
+
getEvent,
|
|
911
|
+
getViewEvents,
|
|
912
|
+
getCellOverlappingEvents,
|
|
913
|
+
getEventsInRange,
|
|
914
|
+
createEvent,
|
|
915
|
+
deleteEvent,
|
|
916
|
+
isEventInRange,
|
|
917
|
+
handleEventResize,
|
|
918
|
+
// Refresh an event's metadata after its dates change (drag/resize).
|
|
919
|
+
refreshEventMeta: (event) => injectMetaData(event),
|
|
920
|
+
};
|
|
921
|
+
};
|