inviton-powerduck 0.0.178 → 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
- let afterAnimFired = false
2392
+ let afterAnimFired = false
2091
2393
  const afterAnim = function () {
2092
- if (afterAnimFired) {
2093
- return;
2094
- }
2394
+ if (afterAnimFired) {
2395
+ return;
2396
+ }
2095
2397
 
2096
- afterAnimFired = true;
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
- clearTimeout(timeout)
2114
- afterAnim()
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 = '&gt;';
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">`
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "inviton-powerduck",
3
3
  "type": "module",
4
- "version": "0.0.178",
4
+ "version": "0.0.179",
5
5
  "files": [
6
6
  "app/",
7
7
  "common/",