inviton-powerduck 0.0.177 → 0.0.179
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.
|
@@ -107,14 +107,6 @@
|
|
|
107
107
|
position: relative;
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
.date-range-picker-wrapper .month-wrapper-inner {
|
|
111
|
-
margin-top: -20px;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
.date-range-picker-wrapper .month-wrapper-inner table {
|
|
115
|
-
margin-top: 20px;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
110
|
.date-range-picker-root.date-range-picker-modalmode .date-range-picker-wrapper {
|
|
119
111
|
margin: auto;
|
|
120
112
|
}
|
|
@@ -432,6 +432,7 @@ import { globalState } from '../../../../app/global-state';
|
|
|
432
432
|
customValueLabel: string
|
|
433
433
|
customValues: any[]
|
|
434
434
|
getCellHtml?: (args: DaterangePickerArgsCustomCellRenderArgs) => string;
|
|
435
|
+
enableSwipeDebug: boolean; // Enable mouse dragging to simulate touch swipe (for debugging)
|
|
435
436
|
showDateFilter?: (date: Temporal.PlainDateTime, day: number) => string | number
|
|
436
437
|
}
|
|
437
438
|
|
|
@@ -508,6 +509,7 @@ import { globalState } from '../../../../app/global-state';
|
|
|
508
509
|
customArrowNextSymbol: null,
|
|
509
510
|
monthSelect: false,
|
|
510
511
|
yearSelect: false,
|
|
512
|
+
enableSwipeDebug: false, // Enable mouse dragging to simulate touch swipe (for debugging)
|
|
511
513
|
},
|
|
512
514
|
opt,
|
|
513
515
|
);
|
|
@@ -531,6 +533,10 @@ import { globalState } from '../../../../app/global-state';
|
|
|
531
533
|
singleMonth = ($(window).width() < 480) as any;
|
|
532
534
|
}
|
|
533
535
|
|
|
536
|
+
if (($(window).width() < 480)) {
|
|
537
|
+
singleMonth = true;
|
|
538
|
+
}
|
|
539
|
+
|
|
534
540
|
if (singleMonth) {
|
|
535
541
|
opt.stickyMonths = false;
|
|
536
542
|
}
|
|
@@ -827,6 +833,302 @@ import { globalState } from '../../../../app/global-state';
|
|
|
827
833
|
showSelectedDays();
|
|
828
834
|
}
|
|
829
835
|
|
|
836
|
+
// Add swipe support for mobile date navigation with preview
|
|
837
|
+
// Debug: Set enableSwipeDebug: true in options to enable mouse dragging simulation
|
|
838
|
+
const enableSwipe = opt.isTouchDevice || opt.enableSwipeDebug;
|
|
839
|
+
|
|
840
|
+
if (enableSwipe) {
|
|
841
|
+
let touchStartX = 0;
|
|
842
|
+
let touchStartY = 0;
|
|
843
|
+
let touchEndX = 0;
|
|
844
|
+
let touchEndY = 0;
|
|
845
|
+
let isSwiping = false;
|
|
846
|
+
let swipeDirection: 'left' | 'right' | null = null;
|
|
847
|
+
const monthWrapperInner = box.find('.month-wrapper-inner');
|
|
848
|
+
let previewMonthContainer: JQuery<HTMLElement> = null;
|
|
849
|
+
|
|
850
|
+
const createPreviewMonth = (direction: 'left' | 'right') => {
|
|
851
|
+
// Clean up any existing preview
|
|
852
|
+
if (previewMonthContainer) {
|
|
853
|
+
previewMonthContainer.remove();
|
|
854
|
+
previewMonthContainer = null;
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
let previewDate: Temporal.PlainDateTime;
|
|
858
|
+
|
|
859
|
+
if (direction === 'right') {
|
|
860
|
+
// Swiping right shows previous month
|
|
861
|
+
previewDate = prevMonth(opt.month1);
|
|
862
|
+
if (isMonthOutOfBounds(previewDate)) return;
|
|
863
|
+
} else {
|
|
864
|
+
// Swipe left shows next month
|
|
865
|
+
previewDate = opt.singleDate || opt.singleMonth
|
|
866
|
+
? nextMonth(opt.month1)
|
|
867
|
+
: nextMonth(opt.month2);
|
|
868
|
+
if (isMonthOutOfBounds(previewDate)) return;
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
// Clone the entire month-wrapper-inner to get exact same structure
|
|
872
|
+
previewMonthContainer = monthWrapperInner.clone();
|
|
873
|
+
previewMonthContainer.removeClass().addClass('swipe-preview-month-wrapper-inner month-wrapper-inner-common');
|
|
874
|
+
|
|
875
|
+
// Update only the first month's content (since we're showing single month preview)
|
|
876
|
+
const monthName = nameMonth(previewDate.month);
|
|
877
|
+
previewMonthContainer.find('.month1 .month-name').html(`${monthName}${opt.hideYearInMonthName ? '' : ` ${previewDate.year}`}`);
|
|
878
|
+
previewMonthContainer.find('.month1 tbody').html(createMonthHTML(previewDate));
|
|
879
|
+
|
|
880
|
+
// Hide month2 if it exists in the clone
|
|
881
|
+
previewMonthContainer.find('.month2').hide();
|
|
882
|
+
previewMonthContainer.find('.gap').hide();
|
|
883
|
+
|
|
884
|
+
// Calculate exact pixel position to avoid gaps
|
|
885
|
+
const containerWidth = monthWrapperInner.outerWidth(true); // Include margins
|
|
886
|
+
const leftPosition = direction === 'right' ? -containerWidth : containerWidth;
|
|
887
|
+
|
|
888
|
+
// Position preview based on swipe direction - use exact pixel positioning
|
|
889
|
+
previewMonthContainer.css({
|
|
890
|
+
position: 'absolute',
|
|
891
|
+
top: monthWrapperInner.position().top + 'px',
|
|
892
|
+
left: leftPosition + 'px',
|
|
893
|
+
width: monthWrapperInner.outerWidth() + 'px',
|
|
894
|
+
pointerEvents: 'none',
|
|
895
|
+
transform: 'translateX(0)', // Start with no transform offset
|
|
896
|
+
'margin-top': monthWrapperInner.css('margin-top'),
|
|
897
|
+
'margin-bottom': monthWrapperInner.css('margin-bottom'),
|
|
898
|
+
'margin-left': '0',
|
|
899
|
+
'margin-right': '0'
|
|
900
|
+
});
|
|
901
|
+
|
|
902
|
+
// Append as sibling to monthWrapperInner (same parent)
|
|
903
|
+
monthWrapperInner.parent().append(previewMonthContainer);
|
|
904
|
+
};
|
|
905
|
+
|
|
906
|
+
// Setup container for swipe - add overflow hidden and relative positioning
|
|
907
|
+
const monthWrapper = box.find('.month-wrapper');
|
|
908
|
+
monthWrapper.css({
|
|
909
|
+
'overflow': 'hidden',
|
|
910
|
+
'position': 'relative'
|
|
911
|
+
});
|
|
912
|
+
|
|
913
|
+
// Helper function to handle start event (touch or mouse)
|
|
914
|
+
const handleDragStart = (clientX: number, clientY: number) => {
|
|
915
|
+
touchStartX = clientX;
|
|
916
|
+
touchStartY = clientY;
|
|
917
|
+
touchEndX = clientX;
|
|
918
|
+
touchEndY = clientY;
|
|
919
|
+
isSwiping = false;
|
|
920
|
+
swipeDirection = null;
|
|
921
|
+
|
|
922
|
+
// Remove transition for immediate response
|
|
923
|
+
monthWrapperInner.css('transition', 'none');
|
|
924
|
+
if (previewMonthContainer) {
|
|
925
|
+
previewMonthContainer.css('transition', 'none');
|
|
926
|
+
}
|
|
927
|
+
};
|
|
928
|
+
|
|
929
|
+
box.find('.month-wrapper').on('touchstart', (e) => {
|
|
930
|
+
const touch = e.touches?.[0] || (e as any).originalEvent?.touches?.[0];
|
|
931
|
+
if (touch) {
|
|
932
|
+
handleDragStart(touch.clientX, touch.clientY);
|
|
933
|
+
}
|
|
934
|
+
});
|
|
935
|
+
|
|
936
|
+
// Mouse drag support (debug mode)
|
|
937
|
+
if (opt.enableSwipeDebug) {
|
|
938
|
+
let isMouseDown = false;
|
|
939
|
+
|
|
940
|
+
box.find('.month-wrapper').on('mousedown', (e) => {
|
|
941
|
+
isMouseDown = true;
|
|
942
|
+
handleDragStart(e.clientX, e.clientY);
|
|
943
|
+
e.preventDefault(); // Prevent text selection
|
|
944
|
+
});
|
|
945
|
+
|
|
946
|
+
$(document).on('mouseup', () => {
|
|
947
|
+
if (isMouseDown && isSwiping) {
|
|
948
|
+
isMouseDown = false;
|
|
949
|
+
// Trigger the same end logic as touchend
|
|
950
|
+
box.find('.month-wrapper').trigger('dragend');
|
|
951
|
+
}
|
|
952
|
+
isMouseDown = false;
|
|
953
|
+
});
|
|
954
|
+
|
|
955
|
+
box.find('.month-wrapper').on('mousemove', (e) => {
|
|
956
|
+
if (!isMouseDown) return;
|
|
957
|
+
|
|
958
|
+
touchEndX = e.clientX;
|
|
959
|
+
touchEndY = e.clientY;
|
|
960
|
+
|
|
961
|
+
const deltaX = touchEndX - touchStartX;
|
|
962
|
+
const deltaY = touchEndY - touchStartY;
|
|
963
|
+
const absDeltaX = Math.abs(deltaX);
|
|
964
|
+
const absDeltaY = Math.abs(deltaY);
|
|
965
|
+
|
|
966
|
+
// Only apply visual feedback if horizontal swipe is dominant
|
|
967
|
+
if (absDeltaX > absDeltaY && absDeltaX > 10) {
|
|
968
|
+
if (!isSwiping) {
|
|
969
|
+
isSwiping = true;
|
|
970
|
+
swipeDirection = deltaX > 0 ? 'right' : 'left';
|
|
971
|
+
createPreviewMonth(swipeDirection);
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
// Apply transform to show dragging effect - both move at same speed
|
|
975
|
+
monthWrapperInner.css('transform', `translateX(${deltaX}px)`);
|
|
976
|
+
|
|
977
|
+
// Move preview container in sync at the same speed
|
|
978
|
+
if (previewMonthContainer) {
|
|
979
|
+
const baseOffset = swipeDirection === 'right' ? '-100%' : '100%';
|
|
980
|
+
previewMonthContainer.css({
|
|
981
|
+
'left': baseOffset,
|
|
982
|
+
'transform': `translateX(${deltaX}px)`
|
|
983
|
+
});
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
e.preventDefault();
|
|
987
|
+
}
|
|
988
|
+
});
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
box.find('.month-wrapper').on('touchmove', (e) => {
|
|
992
|
+
const touch = e.touches?.[0] || (e as any).originalEvent?.touches?.[0];
|
|
993
|
+
if (touch) {
|
|
994
|
+
touchEndX = touch.clientX;
|
|
995
|
+
touchEndY = touch.clientY;
|
|
996
|
+
|
|
997
|
+
const deltaX = touchEndX - touchStartX;
|
|
998
|
+
const deltaY = touchEndY - touchStartY;
|
|
999
|
+
const absDeltaX = Math.abs(deltaX);
|
|
1000
|
+
const absDeltaY = Math.abs(deltaY);
|
|
1001
|
+
|
|
1002
|
+
// Only apply visual feedback if horizontal swipe is dominant
|
|
1003
|
+
if (absDeltaX > absDeltaY && absDeltaX > 10) {
|
|
1004
|
+
if (!isSwiping) {
|
|
1005
|
+
isSwiping = true;
|
|
1006
|
+
swipeDirection = deltaX > 0 ? 'right' : 'left';
|
|
1007
|
+
createPreviewMonth(swipeDirection);
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
// Apply transform to show dragging effect - both move at same speed
|
|
1011
|
+
monthWrapperInner.css('transform', `translateX(${deltaX}px)`);
|
|
1012
|
+
|
|
1013
|
+
// Move preview container in sync at the same speed
|
|
1014
|
+
if (previewMonthContainer) {
|
|
1015
|
+
// Preview starts at -100% (left) or 100% (right) of container width
|
|
1016
|
+
// As we drag, it moves the same distance as the main calendar
|
|
1017
|
+
const baseOffset = swipeDirection === 'right' ? '-100%' : '100%';
|
|
1018
|
+
previewMonthContainer.css({
|
|
1019
|
+
'left': baseOffset,
|
|
1020
|
+
'transform': `translateX(${deltaX}px)`
|
|
1021
|
+
});
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
// Prevent default scrolling when swiping horizontally
|
|
1025
|
+
e.preventDefault();
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
});
|
|
1029
|
+
|
|
1030
|
+
// Shared drag end logic for both touch and mouse
|
|
1031
|
+
const handleDragEnd = () => {
|
|
1032
|
+
const deltaX = touchEndX - touchStartX;
|
|
1033
|
+
const deltaY = touchEndY - touchStartY;
|
|
1034
|
+
const absDeltaX = Math.abs(deltaX);
|
|
1035
|
+
const absDeltaY = Math.abs(deltaY);
|
|
1036
|
+
|
|
1037
|
+
// Calculate if user dragged past 40% of the width
|
|
1038
|
+
const containerWidth = monthWrapperInner.width();
|
|
1039
|
+
const dragThreshold = containerWidth * 0.4;
|
|
1040
|
+
const shouldChangeMonth = isSwiping && absDeltaX > dragThreshold && absDeltaX > absDeltaY;
|
|
1041
|
+
|
|
1042
|
+
if (shouldChangeMonth) {
|
|
1043
|
+
// Add smooth transition for the slide completion
|
|
1044
|
+
monthWrapperInner.css('transition', 'transform 0.3s ease-out');
|
|
1045
|
+
if (previewMonthContainer) {
|
|
1046
|
+
previewMonthContainer.css('transition', 'transform 0.3s ease-out');
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
// Complete the slide animation
|
|
1050
|
+
const fullDistance = deltaX > 0 ? containerWidth : -containerWidth;
|
|
1051
|
+
monthWrapperInner.css('transform', `translateX(${fullDistance}px)`);
|
|
1052
|
+
if (previewMonthContainer) {
|
|
1053
|
+
previewMonthContainer.css('transform', `translateX(${fullDistance}px)`);
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
// After animation, change the month and reset
|
|
1057
|
+
setTimeout(() => {
|
|
1058
|
+
if (deltaX > 0) {
|
|
1059
|
+
// Swipe right - go to previous month
|
|
1060
|
+
const prevButton = box.find('.month1 .prev');
|
|
1061
|
+
if (prevButton.length > 0) {
|
|
1062
|
+
if (!opt.stickyMonths) {
|
|
1063
|
+
gotoPrevMonth(prevButton[0]);
|
|
1064
|
+
} else {
|
|
1065
|
+
gotoPrevMonth_stickily(prevButton[0]);
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
} else {
|
|
1069
|
+
// Swipe left - go to next month
|
|
1070
|
+
const nextButton = opt.singleDate || opt.singleMonth
|
|
1071
|
+
? box.find('.month1 .next')
|
|
1072
|
+
: box.find('.month2 .next');
|
|
1073
|
+
if (nextButton.length > 0) {
|
|
1074
|
+
if (!opt.stickyMonths) {
|
|
1075
|
+
gotoNextMonth(nextButton[0]);
|
|
1076
|
+
} else {
|
|
1077
|
+
gotoNextMonth_stickily(nextButton[0]);
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
// Clean up
|
|
1083
|
+
monthWrapperInner.css({
|
|
1084
|
+
'transition': 'none',
|
|
1085
|
+
'transform': 'translateX(0)'
|
|
1086
|
+
});
|
|
1087
|
+
if (previewMonthContainer) {
|
|
1088
|
+
previewMonthContainer.remove();
|
|
1089
|
+
previewMonthContainer = null;
|
|
1090
|
+
}
|
|
1091
|
+
}, 300);
|
|
1092
|
+
} else {
|
|
1093
|
+
// Snap back to original position
|
|
1094
|
+
monthWrapperInner.css('transition', 'transform 0.3s ease-out');
|
|
1095
|
+
monthWrapperInner.css('transform', 'translateX(0)');
|
|
1096
|
+
|
|
1097
|
+
if (previewMonthContainer) {
|
|
1098
|
+
previewMonthContainer.css('transition', 'transform 0.3s ease-out');
|
|
1099
|
+
previewMonthContainer.css('transform', 'translateX(0)');
|
|
1100
|
+
|
|
1101
|
+
setTimeout(() => {
|
|
1102
|
+
if (previewMonthContainer) {
|
|
1103
|
+
previewMonthContainer.remove();
|
|
1104
|
+
previewMonthContainer = null;
|
|
1105
|
+
}
|
|
1106
|
+
}, 300);
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
// Reset values
|
|
1111
|
+
touchStartX = 0;
|
|
1112
|
+
touchStartY = 0;
|
|
1113
|
+
touchEndX = 0;
|
|
1114
|
+
touchEndY = 0;
|
|
1115
|
+
isSwiping = false;
|
|
1116
|
+
swipeDirection = null;
|
|
1117
|
+
};
|
|
1118
|
+
|
|
1119
|
+
// Attach touchend handler
|
|
1120
|
+
box.find('.month-wrapper').on('touchend', () => {
|
|
1121
|
+
handleDragEnd();
|
|
1122
|
+
});
|
|
1123
|
+
|
|
1124
|
+
// Attach dragend handler for mouse (debug mode)
|
|
1125
|
+
if (opt.enableSwipeDebug) {
|
|
1126
|
+
box.find('.month-wrapper').on('dragend', () => {
|
|
1127
|
+
handleDragEnd();
|
|
1128
|
+
});
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
|
|
830
1132
|
box.attr('unselectable', 'on')
|
|
831
1133
|
.css('user-select', 'none')
|
|
832
1134
|
.bind('selectstart', (e) => {
|
|
@@ -2087,13 +2389,13 @@ import { globalState } from '../../../../app/global-state';
|
|
|
2087
2389
|
return;
|
|
2088
2390
|
}
|
|
2089
2391
|
|
|
2090
|
-
|
|
2392
|
+
let afterAnimFired = false
|
|
2091
2393
|
const afterAnim = function () {
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2394
|
+
if (afterAnimFired) {
|
|
2395
|
+
return;
|
|
2396
|
+
}
|
|
2095
2397
|
|
|
2096
|
-
|
|
2398
|
+
afterAnimFired = true;
|
|
2097
2399
|
box.hide();
|
|
2098
2400
|
$(self).data('date-picker-opened', false);
|
|
2099
2401
|
$(self).trigger('datepicker-closed', {
|
|
@@ -2110,8 +2412,8 @@ import { globalState } from '../../../../app/global-state';
|
|
|
2110
2412
|
box.addClass('pd-dropdown-close-animation');
|
|
2111
2413
|
const timeout = setTimeout(afterAnim, 450)
|
|
2112
2414
|
box.one('animationend', () => {
|
|
2113
|
-
|
|
2114
|
-
|
|
2415
|
+
clearTimeout(timeout)
|
|
2416
|
+
afterAnim()
|
|
2115
2417
|
});
|
|
2116
2418
|
}
|
|
2117
2419
|
|
|
@@ -2204,7 +2506,7 @@ import { globalState } from '../../../../app/global-state';
|
|
|
2204
2506
|
let arrowNext = '>';
|
|
2205
2507
|
if (opt.customArrowNextSymbol) { arrowNext = opt.customArrowNextSymbol; }
|
|
2206
2508
|
|
|
2207
|
-
html += `<div class="month-wrapper"><div class="month-wrapper-inner">`
|
|
2509
|
+
html += `<div class="month-wrapper"><div class="month-wrapper-inner month-wrapper-inner-common">`
|
|
2208
2510
|
+ ` <table class="month1" cellspacing="0" border="0" cellpadding="0">`
|
|
2209
2511
|
+ ` <thead>`
|
|
2210
2512
|
+ ` <tr class="caption">`
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { VNode } from 'vue';
|
|
1
2
|
import type { ModalOnBeforeShownArgs, ModalOnShownArgs } from './modal-utils';
|
|
2
3
|
import { Modal as BootstrapModal } from 'bootstrap';
|
|
3
4
|
import { Prop, toNative } from 'vue-facing-decorator';
|
|
@@ -60,6 +61,7 @@ declare global {
|
|
|
60
61
|
export class ModalConfig {
|
|
61
62
|
static defaultPortalTarget = 'body';
|
|
62
63
|
static defaultMobileMode = ModalMobileMode.BottomSheetModal;
|
|
64
|
+
static renderModalHeaderIcon: (icon: ModalHeaderIcon) => VNode = null;
|
|
63
65
|
}
|
|
64
66
|
|
|
65
67
|
@Component
|
|
@@ -281,6 +283,7 @@ class ModalComponent extends TsxComponent<ModalArgs> implements ModalArgs {
|
|
|
281
283
|
</div>
|
|
282
284
|
|
|
283
285
|
<LoadingIndicator visible={this.blocked} />
|
|
286
|
+
|
|
284
287
|
<div class={`modal-header${this.icon == null ? '' : ' modal-has-headericon'}`}>
|
|
285
288
|
{this.icon != null && <div class="modal-header-icon">{this.renderModalHeaderIcon()}</div>}
|
|
286
289
|
|
|
@@ -300,6 +303,10 @@ class ModalComponent extends TsxComponent<ModalArgs> implements ModalArgs {
|
|
|
300
303
|
}
|
|
301
304
|
|
|
302
305
|
renderModalHeaderIcon() {
|
|
306
|
+
if (ModalConfig.renderModalHeaderIcon != null) {
|
|
307
|
+
return ModalConfig.renderModalHeaderIcon(this.icon);
|
|
308
|
+
}
|
|
309
|
+
|
|
303
310
|
if (this.icon == ModalHeaderIcon.Warning) {
|
|
304
311
|
return <ModalIconWarning visible={true} />;
|
|
305
312
|
} else if (this.icon == ModalHeaderIcon.Success) {
|