funda-ui 4.7.730 → 4.7.735

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.
@@ -247,6 +247,7 @@ const EventCalendarTimeline = (props: EventCalendarTimelineProps) => {
247
247
  //
248
248
  const now = useMemo(() => new Date(), []);
249
249
  const [date, setDate] = useState<Date>(now);
250
+ const prevDateRef = useRef<Date | null>(null);
250
251
  const [day, setDay] = useState<number>(date.getDate());
251
252
  const [month, setMonth] = useState<number>(date.getMonth());
252
253
  const [year, setYear] = useState<number>(date.getFullYear());
@@ -291,6 +292,10 @@ const EventCalendarTimeline = (props: EventCalendarTimelineProps) => {
291
292
  const [tempDate, setTempDate] = useState<string>('');
292
293
 
293
294
 
295
+ // Track all pending requestAnimationFrame IDs for cleanup on unmount
296
+ const rafIdsRef = useRef<Set<number>>(new Set());
297
+
298
+
294
299
 
295
300
  // Open temporary storage for pop-ups
296
301
  const [tableRowNum, setTableRowNum] = useState<number>(-1);
@@ -901,6 +906,7 @@ const EventCalendarTimeline = (props: EventCalendarTimelineProps) => {
901
906
  let mouseDown: boolean = false;
902
907
  let startX: any = 0;
903
908
  let scrollLeft: any = 0;
909
+ const tableDragRafIdRef = useRef<number | null>(null);
904
910
 
905
911
  const handleTableDragStart = useCallback((e: any) => {
906
912
  draggedObj = e.currentTarget;
@@ -920,14 +926,29 @@ const EventCalendarTimeline = (props: EventCalendarTimelineProps) => {
920
926
 
921
927
  mouseDown = false;
922
928
  draggedObj.classList.remove('dragging');
929
+
930
+ // Cancel any pending animation frame
931
+ if (tableDragRafIdRef.current !== null) {
932
+ cancelAnimationFrame(tableDragRafIdRef.current);
933
+ tableDragRafIdRef.current = null;
934
+ }
935
+
923
936
  }, []);
924
937
 
925
938
  const handleTableMove = useCallback((e: any) => {
926
939
  e.preventDefault();
927
940
  if (!mouseDown) { return; }
928
- const x = e.pageX - draggedObj.offsetLeft;
929
- const scroll = x - startX;
930
- draggedObj.scrollLeft = scrollLeft - scroll;
941
+
942
+
943
+ // Use requestAnimationFrame to throttle scroll updates for better performance
944
+ if (tableDragRafIdRef.current === null) {
945
+ tableDragRafIdRef.current = requestAnimationFrame(() => {
946
+ const x = e.pageX - draggedObj.offsetLeft;
947
+ const scroll = x - startX;
948
+ draggedObj.scrollLeft = scrollLeft - scroll;
949
+ tableDragRafIdRef.current = null;
950
+ });
951
+ }
931
952
  }, []);
932
953
 
933
954
 
@@ -1019,25 +1040,37 @@ const EventCalendarTimeline = (props: EventCalendarTimelineProps) => {
1019
1040
  // ================================================================
1020
1041
  // Calendar
1021
1042
  // ================================================================
1022
- function updateTodayDate(inputDate: Date) {
1043
+ function updateTodayDate(inputDate: Date, prevDate?: Date | null) {
1044
+ const previous = prevDate ?? prevDateRef.current;
1045
+ const hasMonthOrYearChanged =
1046
+ !previous ||
1047
+ previous.getMonth() !== inputDate.getMonth() ||
1048
+ previous.getFullYear() !== inputDate.getFullYear();
1049
+
1050
+ // Always sync the active day value
1023
1051
  setDay(inputDate.getDate());
1024
- setMonth(inputDate.getMonth());
1025
- setYear(inputDate.getFullYear());
1026
- setStartDay(getStartDayOfMonth(inputDate));
1027
1052
 
1028
- // update selector
1029
- setSelectedMonth(inputDate.getMonth());
1030
- setSelectedYear(inputDate.getFullYear());
1053
+ if (hasMonthOrYearChanged) {
1054
+ // Only update month/year related state when it actually changes;
1055
+ // this prevents expensive table re-inits for simple day clicks.
1056
+ setMonth(inputDate.getMonth());
1057
+ setYear(inputDate.getFullYear());
1058
+ setStartDay(getStartDayOfMonth(inputDate));
1031
1059
 
1032
-
1033
- setTimeout(() => {
1034
- // initialize table grid
1035
- tableGridInit();
1060
+ // update selector
1061
+ setSelectedMonth(inputDate.getMonth());
1062
+ setSelectedYear(inputDate.getFullYear());
1036
1063
 
1037
- // The scrollbar position is horizontal
1038
- bodyScrollbarInit();
1039
- }, 500);
1064
+ setTimeout(() => {
1065
+ // initialize table grid
1066
+ tableGridInit();
1067
+
1068
+ // The scrollbar position is horizontal
1069
+ bodyScrollbarInit();
1070
+ }, 500);
1071
+ }
1040
1072
 
1073
+ prevDateRef.current = inputDate;
1041
1074
  }
1042
1075
 
1043
1076
 
@@ -1136,6 +1169,29 @@ const EventCalendarTimeline = (props: EventCalendarTimelineProps) => {
1136
1169
 
1137
1170
  }
1138
1171
  function handleDayChange(e: React.MouseEvent, currentDay: number) {
1172
+ // Avoid triggering a full table re-render when the clicked cell is already
1173
+ // the active day; this becomes expensive with large datasets.
1174
+ if (
1175
+ date.getDate() === currentDay &&
1176
+ date.getMonth() === month &&
1177
+ date.getFullYear() === year
1178
+ ) {
1179
+ return;
1180
+ }
1181
+
1182
+ // !!! Important, performance optimization for large data renderings
1183
+ /*
1184
+ - Previously, every time I clicked on the date, 'setDate' would be called in 'useEffect([date])',
1185
+ and 'tableGridInit + bodyScrollbarInit' would be run regardless of whether it was across months/years,
1186
+ and these recalculations and DOM operations were very time-consuming when 1000+ pieces of data, causing lag.
1187
+
1188
+ - Now remember the last date with 'prevDateRef', reset the month/year related state only when the month or year
1189
+ changes and execute 'tableGridInit/scrollbarInit'. Only 'day' is updated when the date is changed, avoiding
1190
+ the relayout of the entire table and the initialization of the scrollbar.
1191
+
1192
+ -'handleDayChange' still updates 'date', but since the month/year has not changed, it no longer triggers heavy
1193
+ initialization, significantly reducing stuttering when clicking, while the month/year switch triggers a full recount as usual.
1194
+ */
1139
1195
  setDate(new Date(year, month, currentDay));
1140
1196
  }
1141
1197
 
@@ -1871,25 +1927,38 @@ const EventCalendarTimeline = (props: EventCalendarTimelineProps) => {
1871
1927
 
1872
1928
  const tableGridEl: any = tableGridRef.current;
1873
1929
 
1874
- // initialize cell height
1875
- const headerTitleTbody = tableGridEl.querySelector('.custom-event-tl-table__datagrid-body__title tbody');
1876
- const contentTbody = tableGridEl.querySelector('.custom-event-tl-table__datagrid-body__content tbody');
1877
- if (!headerTitleTbody || !contentTbody) return;
1930
+ // Use requestAnimationFrame to batch DOM operations
1931
+ const rafId = requestAnimationFrame(() => {
1932
+
1878
1933
 
1879
- const headerTitleTrElements = headerTitleTbody.getElementsByTagName('tr');
1880
- const trElements = contentTbody.getElementsByTagName('tr');
1934
+ // initialize cell height
1935
+ const headerTitleTbody = tableGridEl.querySelector('.custom-event-tl-table__datagrid-body__title tbody');
1936
+ const contentTbody = tableGridEl.querySelector('.custom-event-tl-table__datagrid-body__content tbody');
1937
+ if (!headerTitleTbody || !contentTbody) return;
1938
+
1939
+ const headerTitleTrElements = headerTitleTbody.getElementsByTagName('tr');
1940
+ const trElements = contentTbody.getElementsByTagName('tr');
1941
+
1942
+ // Reset any previously set inline heights so we measure natural heights.
1943
+ for (let i = 0; i < headerTitleTrElements.length; i++) {
1944
+ // set to 'auto' (or remove inline style) to allow shrink
1945
+ headerTitleTrElements[i].style.height = 'auto';
1946
+ if (trElements[i]) trElements[i].style.height = 'auto';
1947
+
1948
+ const targetElement = headerTitleTrElements[i].offsetHeight > trElements[i].offsetHeight ? headerTitleTrElements[i] : trElements[i];
1949
+ const tdOHeight = window.getComputedStyle(targetElement).height;
1950
+ headerTitleTrElements[i].style.height = tdOHeight;
1951
+ trElements[i].style.height = tdOHeight;
1952
+ }
1953
+
1954
+
1955
+ // Remove from tracking set after execution
1956
+ rafIdsRef.current.delete(rafId);
1957
+ });
1958
+
1959
+ // Track this requestAnimationFrame ID for cleanup
1960
+ rafIdsRef.current.add(rafId);
1881
1961
 
1882
- // Reset any previously set inline heights so we measure natural heights.
1883
- for (let i = 0; i < headerTitleTrElements.length; i++) {
1884
- // set to 'auto' (or remove inline style) to allow shrink
1885
- headerTitleTrElements[i].style.height = 'auto';
1886
- if (trElements[i]) trElements[i].style.height = 'auto';
1887
-
1888
- const targetElement = headerTitleTrElements[i].offsetHeight > trElements[i].offsetHeight ? headerTitleTrElements[i] : trElements[i];
1889
- const tdOHeight = window.getComputedStyle(targetElement).height;
1890
- headerTitleTrElements[i].style.height = tdOHeight;
1891
- trElements[i].style.height = tdOHeight;
1892
- }
1893
1962
 
1894
1963
 
1895
1964
  }
@@ -1909,223 +1978,234 @@ const EventCalendarTimeline = (props: EventCalendarTimelineProps) => {
1909
1978
  _curColCount = 7;
1910
1979
  }
1911
1980
 
1912
- //****************
1913
- // STEP 1-1:
1914
- //****************
1915
- // calculate min width (MODE: WEEK)
1916
- //--------------
1917
- if (appearanceMode === 'week') {
1918
- const tableMaxWidth = tableGridEl.clientWidth;
1919
- const tableHeaderTitleWidth = tableGridEl.querySelector('.custom-event-tl-table__cell-cushion-headertitle').clientWidth;
1920
- const tableDividerWidth = tableGridEl.querySelector('.custom-event-tl-table__timeline-divider').clientWidth;
1921
- const tableBorderWidth = 4;
1922
- const scrollMaxWidth = tableMaxWidth - tableHeaderTitleWidth - tableDividerWidth - tableBorderWidth;
1981
+ // Use requestAnimationFrame to batch DOM operations
1982
+ const rafId = requestAnimationFrame(() => {
1983
+
1923
1984
 
1924
- _curCellMinWidth = scrollMaxWidth / 7;
1925
- _curColCount = 7;
1985
+ //****************
1986
+ // STEP 1-1:
1987
+ //****************
1988
+ // calculate min width (MODE: WEEK)
1989
+ //--------------
1990
+ if (appearanceMode === 'week') {
1991
+ const tableMaxWidth = tableGridEl.clientWidth;
1992
+ const tableHeaderTitleWidth = tableGridEl.querySelector('.custom-event-tl-table__cell-cushion-headertitle').clientWidth;
1993
+ const tableDividerWidth = tableGridEl.querySelector('.custom-event-tl-table__timeline-divider').clientWidth;
1994
+ const tableBorderWidth = 4;
1995
+ const scrollMaxWidth = tableMaxWidth - tableHeaderTitleWidth - tableDividerWidth - tableBorderWidth;
1926
1996
 
1927
- // header
1928
- tableGridEl.querySelectorAll('.custom-event-tl-table__cell-cushion-headercontent__container, .custom-event-tl-table__cell-cushion-content').forEach((node: HTMLDivElement) => {
1929
- node.style.width = _curCellMinWidth + 'px';
1930
- });
1997
+ _curCellMinWidth = scrollMaxWidth / 7;
1998
+ _curColCount = 7;
1931
1999
 
2000
+ // header
2001
+ tableGridEl.querySelectorAll('.custom-event-tl-table__cell-cushion-headercontent__container, .custom-event-tl-table__cell-cushion-content').forEach((node: HTMLDivElement) => {
2002
+ node.style.width = _curCellMinWidth + 'px';
2003
+ });
1932
2004
 
1933
- }
1934
2005
 
2006
+ }
1935
2007
 
1936
2008
 
1937
- //****************
1938
- // STEP 1-2:
1939
- //****************
1940
- // calculate min width (MODE: MONTH)
1941
- //--------------
1942
- const cellMinWidth = _curCellMinWidth;
1943
- const colCount = _curColCount;
1944
- const scrollableMinWidth = cellMinWidth * colCount;
1945
2009
 
2010
+ //****************
2011
+ // STEP 1-2:
2012
+ //****************
2013
+ // calculate min width (MODE: MONTH)
2014
+ //--------------
2015
+ const cellMinWidth = _curCellMinWidth;
2016
+ const colCount = _curColCount;
2017
+ const scrollableMinWidth = cellMinWidth * colCount;
1946
2018
 
1947
- //****************
1948
- // STEP 1-3:
1949
- //****************
1950
- // initialize "header & main" cells
1951
- //--------------
1952
- const headerThContentContainers: any = tableGridEl.querySelector('.custom-event-tl-table__datagrid-header__content tbody').getElementsByTagName('th');
1953
- for (let i = 0; i < headerThContentContainers.length; i++) {
1954
- const curHeaderThContent = headerThContentContainers[i].querySelector('.custom-event-tl-table__cell-cushion-headercontent');
1955
- if (curHeaderThContent !== null) curHeaderThContent.style.width = _curCellMinWidth + 'px';
1956
- }
1957
2019
 
2020
+ //****************
2021
+ // STEP 1-3:
2022
+ //****************
2023
+ // initialize "header & main" cells
2024
+ //--------------
2025
+ const headerThContentContainers: any = tableGridEl.querySelector('.custom-event-tl-table__datagrid-header__content tbody').getElementsByTagName('th');
2026
+ for (let i = 0; i < headerThContentContainers.length; i++) {
2027
+ const curHeaderThContent = headerThContentContainers[i].querySelector('.custom-event-tl-table__cell-cushion-headercontent');
2028
+ if (curHeaderThContent !== null) curHeaderThContent.style.width = _curCellMinWidth + 'px';
2029
+ }
1958
2030
 
1959
- const mainTdContentContainers: any = tableGridEl.querySelector('.custom-event-tl-table__datagrid-body__content tbody').getElementsByTagName('td');
1960
- for (let i = 0; i < mainTdContentContainers.length; i++) {
1961
- const curHeaderThContent = mainTdContentContainers[i].querySelector('.custom-event-tl-table__cell-cushion-content');
1962
- if (curHeaderThContent !== null) curHeaderThContent.style.width = _curCellMinWidth + 'px';
1963
- }
1964
2031
 
1965
- const mainTdContentCols: any = tableGridEl.querySelector('.custom-event-tl-table__datagrid-body__content colgroup').getElementsByTagName('col')
1966
- for (let i = 0; i < mainTdContentCols.length; i++) {
1967
- mainTdContentCols[i].style.minWidth = _curCellMinWidth + 'px';
1968
- }
2032
+ const mainTdContentContainers: any = tableGridEl.querySelector('.custom-event-tl-table__datagrid-body__content tbody').getElementsByTagName('td');
2033
+ for (let i = 0; i < mainTdContentContainers.length; i++) {
2034
+ const curHeaderThContent = mainTdContentContainers[i].querySelector('.custom-event-tl-table__cell-cushion-content');
2035
+ if (curHeaderThContent !== null) curHeaderThContent.style.width = _curCellMinWidth + 'px';
2036
+ }
1969
2037
 
2038
+ const mainTdContentCols: any = tableGridEl.querySelector('.custom-event-tl-table__datagrid-body__content colgroup').getElementsByTagName('col')
2039
+ for (let i = 0; i < mainTdContentCols.length; i++) {
2040
+ mainTdContentCols[i].style.minWidth = _curCellMinWidth + 'px';
2041
+ }
1970
2042
 
1971
- //****************
1972
- // STEP 2:
1973
- //****************
1974
- // initialize scrollable wrapper (width)
1975
- //--------------
1976
- const _scrollableWrapper: HTMLElement[] = tableGridEl.querySelectorAll('.custom-event-tl-table__scroller-harness');
1977
- [].slice.call(_scrollableWrapper).forEach((el: any) => {
1978
- const scrollType = el.dataset.scroll;
1979
2043
 
1980
- if (appearanceMode === 'week') {
1981
- el.classList.add('custom-event-tl-table__scroller-harness--hideX');
1982
- }
1983
- if (appearanceMode === 'month') {
1984
- el.classList.remove('custom-event-tl-table__scroller-harness--hideX');
1985
- }
2044
+ //****************
2045
+ // STEP 2:
2046
+ //****************
2047
+ // initialize scrollable wrapper (width)
2048
+ //--------------
2049
+ const _scrollableWrapper: HTMLElement[] = tableGridEl.querySelectorAll('.custom-event-tl-table__scroller-harness');
2050
+ [].slice.call(_scrollableWrapper).forEach((el: any) => {
2051
+ const scrollType = el.dataset.scroll;
1986
2052
 
1987
- if (scrollType !== 'list') {
1988
- const _content = el.querySelector('.custom-event-tl-table__scroller');
1989
- const tableMaxWidth = tableGridEl.clientWidth;
1990
- const tableHeaderTitleWidth = tableGridEl.querySelector('.custom-event-tl-table__cell-cushion-headertitle').clientWidth;
1991
- const tableDividerWidth = tableGridEl.querySelector('.custom-event-tl-table__timeline-divider').clientWidth;
1992
- const tableBorderWidth = 4;
1993
- const scrollMaxWidth = tableMaxWidth - tableHeaderTitleWidth - tableDividerWidth - tableBorderWidth;
2053
+ if (appearanceMode === 'week') {
2054
+ el.classList.add('custom-event-tl-table__scroller-harness--hideX');
2055
+ }
2056
+ if (appearanceMode === 'month') {
2057
+ el.classList.remove('custom-event-tl-table__scroller-harness--hideX');
2058
+ }
1994
2059
 
1995
- el.dataset.width = scrollMaxWidth;
1996
- el.style.maxWidth = el.dataset.width + 'px';
1997
- _content.style.minWidth = scrollableMinWidth + 'px';
2060
+ if (scrollType !== 'list') {
2061
+ const _content = el.querySelector('.custom-event-tl-table__scroller');
2062
+ const tableMaxWidth = tableGridEl.clientWidth;
2063
+ const tableHeaderTitleWidth = tableGridEl.querySelector('.custom-event-tl-table__cell-cushion-headertitle').clientWidth;
2064
+ const tableDividerWidth = tableGridEl.querySelector('.custom-event-tl-table__timeline-divider').clientWidth;
2065
+ const tableBorderWidth = 4;
2066
+ const scrollMaxWidth = tableMaxWidth - tableHeaderTitleWidth - tableDividerWidth - tableBorderWidth;
1998
2067
 
1999
- }
2000
- });
2068
+ el.dataset.width = scrollMaxWidth;
2069
+ el.style.maxWidth = el.dataset.width + 'px';
2070
+ _content.style.minWidth = scrollableMinWidth + 'px';
2001
2071
 
2072
+ }
2073
+ });
2002
2074
 
2003
- //****************
2004
- // STEP 3:
2005
- //****************
2006
- // initialize cell width
2007
- //--------------
2008
- const tdElementMaxWidth: number = typeof mainTdContentContainers[0] === 'undefined' ? 0 : parseFloat(window.getComputedStyle(mainTdContentContainers[0].querySelector('.custom-event-tl-table__cell-cushion-content')).maxWidth);
2009
2075
 
2076
+ //****************
2077
+ // STEP 3:
2078
+ //****************
2079
+ // initialize cell width
2080
+ //--------------
2081
+ const tdElementMaxWidth: number = typeof mainTdContentContainers[0] === 'undefined' ? 0 : parseFloat(window.getComputedStyle(mainTdContentContainers[0].querySelector('.custom-event-tl-table__cell-cushion-content')).maxWidth);
2010
2082
 
2011
- if (Array.isArray(eventsValue) && eventsValue.length > 0) {
2012
2083
 
2013
- for (let i = 0; i < headerThContentContainers.length; i++) {
2084
+ if (Array.isArray(eventsValue) && eventsValue.length > 0) {
2014
2085
 
2015
- const curHeaderThContent = headerThContentContainers[i].querySelector('.custom-event-tl-table__cell-cushion-headercontent');
2016
- const curHeaderThContentMaxWidth = parseFloat(window.getComputedStyle(curHeaderThContent).width);
2017
- const targetElement = headerThContentContainers[i].offsetWidth > mainTdContentContainers[i].offsetWidth ? headerThContentContainers[i] : mainTdContentContainers[i];
2018
- let tdOwidth = parseFloat(window.getComputedStyle(targetElement).width);
2086
+ for (let i = 0; i < headerThContentContainers.length; i++) {
2019
2087
 
2088
+ const curHeaderThContent = headerThContentContainers[i].querySelector('.custom-event-tl-table__cell-cushion-headercontent');
2089
+ const curHeaderThContentMaxWidth = parseFloat(window.getComputedStyle(curHeaderThContent).width);
2090
+ const targetElement = headerThContentContainers[i].offsetWidth > mainTdContentContainers[i].offsetWidth ? headerThContentContainers[i] : mainTdContentContainers[i];
2091
+ let tdOwidth = parseFloat(window.getComputedStyle(targetElement).width);
2020
2092
 
2021
- // check td max width
2022
- if (tdElementMaxWidth > 0 && tdOwidth > tdElementMaxWidth) {
2023
- tdOwidth = tdElementMaxWidth;
2024
- }
2025
2093
 
2026
- // check header th max width
2027
- if (tdElementMaxWidth > 0 && tdElementMaxWidth < curHeaderThContentMaxWidth) {
2028
- tdOwidth = curHeaderThContentMaxWidth;
2029
- }
2094
+ // check td max width
2095
+ if (tdElementMaxWidth > 0 && tdOwidth > tdElementMaxWidth) {
2096
+ tdOwidth = tdElementMaxWidth;
2097
+ }
2098
+
2099
+ // check header th max width
2100
+ if (tdElementMaxWidth > 0 && tdElementMaxWidth < curHeaderThContentMaxWidth) {
2101
+ tdOwidth = curHeaderThContentMaxWidth;
2102
+ }
2030
2103
 
2031
- // Prevent the width from being +1 each time it is initialized
2032
- tdOwidth = tdOwidth - 1;
2104
+ // Prevent the width from being +1 each time it is initialized
2105
+ tdOwidth = tdOwidth - 1;
2033
2106
 
2034
2107
 
2035
- headerThContentContainers[i].querySelector('.custom-event-tl-table__cell-cushion-headercontent').style.width = tdOwidth + 'px';
2036
- mainTdContentCols[i].style.minWidth = tdOwidth + 'px';
2108
+ headerThContentContainers[i].querySelector('.custom-event-tl-table__cell-cushion-headercontent').style.width = tdOwidth + 'px';
2109
+ mainTdContentCols[i].style.minWidth = tdOwidth + 'px';
2037
2110
 
2038
2111
 
2112
+ }
2039
2113
  }
2040
- }
2041
2114
 
2042
2115
 
2043
- //****************
2044
- // STEP 4:
2045
- //****************
2046
- // initialize max width of table content
2047
- //--------------
2048
- if (scrollBodyRef.current !== null && scrollHeaderRef.current !== null) {
2049
- const tableContentWidth = window.getComputedStyle(tableGridEl.querySelector('.custom-event-tl-table__datagrid-body__content')).width;
2050
- const scrollBodyEl: any = scrollBodyRef.current;
2051
- const scrollHeaderEl: any = scrollHeaderRef.current;
2116
+ //****************
2117
+ // STEP 4:
2118
+ //****************
2119
+ // initialize max width of table content
2120
+ //--------------
2121
+ if (scrollBodyRef.current !== null && scrollHeaderRef.current !== null) {
2122
+ const tableContentWidth = window.getComputedStyle(tableGridEl.querySelector('.custom-event-tl-table__datagrid-body__content')).width;
2123
+ const scrollBodyEl: any = scrollBodyRef.current;
2124
+ const scrollHeaderEl: any = scrollHeaderRef.current;
2052
2125
 
2053
- scrollBodyEl.style.width = tableContentWidth;
2054
- scrollHeaderEl.style.width = tableContentWidth;
2055
- scrollBodyEl.dataset.width = parseFloat(tableContentWidth);
2056
- scrollHeaderEl.dataset.width = parseFloat(tableContentWidth);
2126
+ scrollBodyEl.style.width = tableContentWidth;
2127
+ scrollHeaderEl.style.width = tableContentWidth;
2128
+ scrollBodyEl.dataset.width = parseFloat(tableContentWidth);
2129
+ scrollHeaderEl.dataset.width = parseFloat(tableContentWidth);
2057
2130
 
2058
- //
2059
- const tableWrapperMaxWidthLatest = tableGridEl.clientWidth;
2060
- if (tableWrapperMaxWidthLatest > parseFloat(tableContentWidth)) {
2061
- tableGridEl.querySelector('.custom-event-tl-table__timeline-table').style.width = tableContentWidth;
2062
- }
2131
+ //
2132
+ const tableWrapperMaxWidthLatest = tableGridEl.clientWidth;
2133
+ if (tableWrapperMaxWidthLatest > parseFloat(tableContentWidth)) {
2134
+ tableGridEl.querySelector('.custom-event-tl-table__timeline-table').style.width = tableContentWidth;
2135
+ }
2063
2136
 
2064
2137
 
2065
- }
2138
+ }
2066
2139
 
2067
2140
 
2068
2141
 
2069
- //****************
2070
- // STEP 5:
2071
- //****************
2072
- // initialize cell height
2073
- //--------------
2074
- tableGridInitHeadertitle();
2142
+ //****************
2143
+ // STEP 5:
2144
+ //****************
2145
+ // initialize cell height
2146
+ //--------------
2147
+ tableGridInitHeadertitle();
2075
2148
 
2076
- //****************
2077
- // STEP 6:
2078
- //****************
2079
- //initialize scrollable wrapper (height)
2080
- //--------------
2081
- [].slice.call(_scrollableWrapper).forEach((el: any) => {
2082
- const scrollType = el.dataset.scroll;
2083
- const oldHeight = el.clientHeight;
2149
+ //****************
2150
+ // STEP 6:
2151
+ //****************
2152
+ //initialize scrollable wrapper (height)
2153
+ //--------------
2154
+ [].slice.call(_scrollableWrapper).forEach((el: any) => {
2155
+ const scrollType = el.dataset.scroll;
2156
+ const oldHeight = el.clientHeight;
2084
2157
 
2085
- if (scrollType !== 'header') {
2086
- const tableWrapperMaxHeight = window.getComputedStyle(tableGridEl as HTMLElement).height;
2087
- if (oldHeight > parseFloat(tableWrapperMaxHeight)) {
2088
- el.style.height = tableWrapperMaxHeight;
2158
+ if (scrollType !== 'header') {
2159
+ const tableWrapperMaxHeight = window.getComputedStyle(tableGridEl as HTMLElement).height;
2160
+ if (oldHeight > parseFloat(tableWrapperMaxHeight)) {
2161
+ el.style.height = tableWrapperMaxHeight;
2162
+ }
2089
2163
  }
2090
- }
2091
2164
 
2092
- });
2165
+ });
2093
2166
 
2094
2167
 
2095
2168
 
2096
- //****************
2097
- // STEP 7:
2098
- //****************
2099
- // display wrapper
2100
- //--------------
2101
- tableGridEl.classList.remove('invisible');
2169
+ //****************
2170
+ // STEP 7:
2171
+ //****************
2172
+ // display wrapper
2173
+ //--------------
2174
+ tableGridEl.classList.remove('invisible');
2102
2175
 
2103
- //****************
2104
- // STEP 1-1:
2105
- //****************
2106
- // calculate min width (MODE: WEEK)
2107
- //--------------
2108
- if (appearanceMode === 'week') {
2109
- const tableMaxWidth = tableGridEl.clientWidth;
2110
- const tableHeaderTitleWidth = tableGridEl.querySelector('.custom-event-tl-table__cell-cushion-headertitle').clientWidth;
2111
- const tableDividerWidth = tableGridEl.querySelector('.custom-event-tl-table__timeline-divider').clientWidth;
2112
- const tableBorderWidth = 4;
2113
- const scrollMaxWidth = tableMaxWidth - tableHeaderTitleWidth - tableDividerWidth - tableBorderWidth;
2176
+ //****************
2177
+ // STEP 1-1:
2178
+ //****************
2179
+ // calculate min width (MODE: WEEK)
2180
+ //--------------
2181
+ if (appearanceMode === 'week') {
2182
+ const tableMaxWidth = tableGridEl.clientWidth;
2183
+ const tableHeaderTitleWidth = tableGridEl.querySelector('.custom-event-tl-table__cell-cushion-headertitle').clientWidth;
2184
+ const tableDividerWidth = tableGridEl.querySelector('.custom-event-tl-table__timeline-divider').clientWidth;
2185
+ const tableBorderWidth = 4;
2186
+ const scrollMaxWidth = tableMaxWidth - tableHeaderTitleWidth - tableDividerWidth - tableBorderWidth;
2114
2187
 
2115
- _curCellMinWidth = scrollMaxWidth / 7;
2116
- _curColCount = 7;
2188
+ _curCellMinWidth = scrollMaxWidth / 7;
2189
+ _curColCount = 7;
2117
2190
 
2118
- // header content
2119
- tableGridEl.querySelectorAll('.custom-event-tl-table__cell-cushion-headercontent__container, .custom-event-tl-table__cell-cushion-headercontent').forEach((node: HTMLDivElement) => {
2120
- node.style.width = _curCellMinWidth + 'px';
2121
- });
2191
+ // header content
2192
+ tableGridEl.querySelectorAll('.custom-event-tl-table__cell-cushion-headercontent__container, .custom-event-tl-table__cell-cushion-headercontent').forEach((node: HTMLDivElement) => {
2193
+ node.style.width = _curCellMinWidth + 'px';
2194
+ });
2122
2195
 
2123
- // main content
2124
- tableGridEl.querySelectorAll('.custom-event-tl-table__cell-cushion-content').forEach((node: HTMLDivElement) => {
2125
- node.style.width = _curCellMinWidth + 'px';
2126
- });
2196
+ // main content
2197
+ tableGridEl.querySelectorAll('.custom-event-tl-table__cell-cushion-content').forEach((node: HTMLDivElement) => {
2198
+ node.style.width = _curCellMinWidth + 'px';
2199
+ });
2127
2200
 
2128
- }
2201
+ }
2202
+
2203
+ // Remove from tracking set after execution
2204
+ rafIdsRef.current.delete(rafId);
2205
+ });
2206
+
2207
+ // Track this requestAnimationFrame ID for cleanup
2208
+ rafIdsRef.current.add(rafId);
2129
2209
 
2130
2210
  }
2131
2211
 
@@ -2172,7 +2252,7 @@ const EventCalendarTimeline = (props: EventCalendarTimelineProps) => {
2172
2252
 
2173
2253
 
2174
2254
  useEffect(() => {
2175
- updateTodayDate(date);
2255
+ updateTodayDate(date, prevDateRef.current);
2176
2256
  }, [date]);
2177
2257
 
2178
2258
 
@@ -2222,6 +2302,18 @@ const EventCalendarTimeline = (props: EventCalendarTimelineProps) => {
2222
2302
  //--------------
2223
2303
  return () => {
2224
2304
 
2305
+ // Cancel all pending requestAnimationFrame callbacks to prevent memory leaks
2306
+ rafIdsRef.current.forEach((rafId) => {
2307
+ cancelAnimationFrame(rafId);
2308
+ });
2309
+ rafIdsRef.current.clear();
2310
+
2311
+ // Cancel table drag animation frame if pending
2312
+ if (tableDragRafIdRef.current !== null) {
2313
+ cancelAnimationFrame(tableDragRafIdRef.current);
2314
+ tableDragRafIdRef.current = null;
2315
+ }
2316
+
2225
2317
  // reset table grid
2226
2318
  tableGridReset();
2227
2319
 
package/package.json CHANGED
@@ -1 +1 @@
1
- {"author":"UIUX Lab","email":"uiuxlab@gmail.com","name":"funda-ui","version":"4.7.730","description":"React components using pure Bootstrap 5+ which does not contain any external style and script libraries.","repository":{"type":"git","url":"git+https://github.com/xizon/funda-ui.git"},"scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"keywords":["bootstrap","react-bootstrap","react-components","components","components-react","react-bootstrap-components","react","funda-ui","fundaui","uikit","ui-kit","ui-components"],"bugs":{"url":"https://github.com/xizon/funda-ui/issues"},"homepage":"https://github.com/xizon/funda-ui#readme","main":"all.js","license":"MIT","dependencies":{"react":"^18.2.0","react-dom":"^18.2.0"},"types":"all.d.ts","publishConfig":{"directory":"lib"},"directories":{"lib":"lib"}}
1
+ {"author":"UIUX Lab","email":"uiuxlab@gmail.com","name":"funda-ui","version":"4.7.735","description":"React components using pure Bootstrap 5+ which does not contain any external style and script libraries.","repository":{"type":"git","url":"git+https://github.com/xizon/funda-ui.git"},"scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"keywords":["bootstrap","react-bootstrap","react-components","components","components-react","react-bootstrap-components","react","funda-ui","fundaui","uikit","ui-kit","ui-components"],"bugs":{"url":"https://github.com/xizon/funda-ui/issues"},"homepage":"https://github.com/xizon/funda-ui#readme","main":"all.js","license":"MIT","dependencies":{"react":"^18.2.0","react-dom":"^18.2.0"},"types":"all.d.ts","publishConfig":{"directory":"lib"},"directories":{"lib":"lib"}}